﻿#include "stdafx.h";
/*
 * Copyright (C) 1998  Mark Baysinger (mbaysing@ucsd.edu)
 * Copyright (C) 1998,1999,2000,2001  Ross Combs (rocombs@cs.nmsu.edu)
 * Copyright (C) 1999  Gediminas (gediminas_lt@mailexcite.com)
 * Copyright (C) 1999  Rob Crittenden (rcrit@greyoak.com)
 * Copyright (C) 2000,2001  Marco Ziech (mmz@gmx.net)
 * Copyright (C) 2000  Dizzy (dizzy@roedu.net)
 * Copyright (C) 2000  Onlyer (onlyer@263.net)
 * Copyright (C) 2003,2004  Aaron
 * Copyright (C) 2004  Donny Redmond (dredmond@linuxmail.org)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
#include "common/setup_before.h"
#include <stdio.h>
#ifdef HAVE_STDDEF_H
# include <stddef.h>
#else
# ifndef NULL
#  define NULL ((void *)0)
# endif
#endif
#ifdef STDC_HEADERS
# include <stdlib.h>
#else
# ifdef HAVE_MALLOC_H
#  include <malloc.h>
# endif
#endif
#include "compat/strtoul.h"
#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
#  include <strings.h>
# endif
#endif
#include "compat/strdup.h"
#include "compat/strcasecmp.h"
#include <ctype.h>
#include <errno.h>
#include "compat/strerror.h"
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif
#ifdef HAVE_SYS_TYPES
# include <sys/types.h>
#endif
#include "compat/strftime.h"
#include "message.h"
#include "common/tag.h"
#include "connection.h"
#include "channel.h"
#include "game.h"
#include "common/util.h"
#include "common/version.h"
#include "team.h"
#include "account.h"
#include "account_wrap.h"
#include "server.h"
#include "prefs.h"
#include "common/eventlog.h"
#include "ladder.h"
#include "timer.h"
#include "common/bnettime.h"
#include "common/addr.h"
#include "common/packet.h"
#include "helpfile.h"
#include "mail.h"
#include "common/bnethash.h"
#include "runprog.h"
#include "common/list.h"
#include "common/proginfo.h"
#include "alias_command.h"
#include "realm.h"
#include "ipban.h"
#include "command_groups.h"
#include "common/queue.h"
#include "common/bn_type.h"
#include "common/xalloc.h"
#include "command.h"
#include "news.h"
#include "common/trans.h"
#include "common/lstr.h"
// aaron
#include "topic.h"
#include "friends.h"
#include "clan.h"
#include "common/setup_after.h"


static char const * bnclass_get_str(unsigned int classs);
static void do_whisper(t_connection * user_c, char const * dest, char const * text);
static void do_whois(t_connection * c, char const * dest);
static void user_timer_cb(t_connection * c, time_t now, t_timer_data str);

char msgtemp[MAX_MESSAGE_LEN];
char msgtemp2[MAX_MESSAGE_LEN];

static char const * bnclass_get_str(unsigned int classs)
{
    switch (classs)
    {
    case PLAYERINFO_DRTL_CLASS_WARRIOR:
        return "warrior";
    case PLAYERINFO_DRTL_CLASS_ROGUE:
        return "rogue";
    case PLAYERINFO_DRTL_CLASS_SORCERER:
        return "sorcerer";
    default:
        return "unknown";
    }
}


static void do_whisper(t_connection * user_c, char const * dest, char const * text)
{
    t_connection * dest_c;
    char const *   tname;

    if (!(dest_c = connlist_find_connection_by_name(dest,conn_get_realm(user_c))))
    {
        message_send_text(user_c,message_type_error,user_c,"That user is not logged on.");
        return;
    }

    if (conn_get_dndstr(dest_c,0))
    {
        sprintf(msgtemp,"%.64s is unavailable (%.128s)",conn_get_username(dest_c),conn_get_dndstr(dest_c,0));
        message_send_text(user_c,message_type_info,user_c,msgtemp);
        return;
    }

    message_send_text(user_c,message_type_whisperack,dest_c,text);

    if (conn_get_awaystr(dest_c))
    {
        sprintf(msgtemp,"%.64s is away (%.128s)",conn_get_username(dest_c),conn_get_awaystr(dest_c));
        message_send_text(user_c,message_type_info,user_c,msgtemp);
    }

    message_send_text(dest_c,message_type_whisper,user_c,text);

    if ((tname = conn_get_username(user_c)))
    {
        char username[1+USER_NAME_MAX]; /* '*' + username (including NUL) */

        if (strlen(tname)<USER_NAME_MAX)
        {
            sprintf(username,"*%s",tname);
            conn_set_lastsender(dest_c,username);
        }
    }
}


static void do_whois(t_connection * c, char const * dest)
{
    t_connection *    dest_c;
    char              namepart[136]; /* 64 + " (" + 64 + ")" + NUL */
    char const *      verb;
    t_game const *    game;
    t_channel const * channel;

    if ((!(dest_c = connlist_find_connection_by_accountname(dest))) &&
            (!(dest_c = connlist_find_connection_by_name(dest,conn_get_realm(c)))))
    {
        t_account * dest_a;
        t_bnettime btlogin;
        time_t ulogin;
        struct tm * tmlogin;

        if (!(dest_a = accountlist_find_account(dest))) {
            message_send_text(c,message_type_error,c,"Unknown user.");
            return;
        }

        if (conn_get_class(c) == conn_class_bnet) {
            btlogin = time_to_bnettime((time_t)account_get_ll_time(dest_a),0);
            btlogin = bnettime_add_tzbias(btlogin, conn_get_tzbias(c));
            ulogin = bnettime_to_time(btlogin);
            if (!(tmlogin = gmtime(&ulogin)))
                strcpy(msgtemp, "User was last seen on ?");
            else
                strftime(msgtemp, sizeof(msgtemp), "User was last seen on : %a %b %d %H:%M:%S",tmlogin);
        } else strcpy(msgtemp, "User is offline");
        message_send_text(c, message_type_info, c, msgtemp);
        return;
    }

    if (c==dest_c)
    {
        strcpy(namepart,"You");
        verb = "are";
    }
    else
    {
        char const * tname;

        sprintf(namepart,"%.64s",(tname = conn_get_chatcharname(dest_c,c)));
        conn_unget_chatcharname(dest_c,tname);
        verb = "is";
    }

    if ((game = conn_get_game(dest_c)))
    {
        sprintf(msgtemp,"%s %s using %s and %s currently in %s game \"%.64s\".",
                namepart,
                verb,
                clienttag_get_title(conn_get_clienttag(dest_c)),
                verb,
                game_get_flag(game) == game_flag_private ? "private" : "",
                game_get_name(game));
    }
    else if ((channel = conn_get_channel(dest_c)))
    {
        sprintf(msgtemp,"%s %s using %s and %s currently in channel \"%.64s\".",
                namepart,
                verb,
                clienttag_get_title(conn_get_clienttag(dest_c)),
                verb,
                channel_get_name(channel));
    }
    else
        sprintf(msgtemp,"%s %s using %s.",
                namepart,
                verb,
                clienttag_get_title(conn_get_clienttag(dest_c)));
    message_send_text(c,message_type_info,c,msgtemp);

    if (conn_get_dndstr(dest_c,0))
    {
        sprintf(msgtemp,"%s %s refusing messages (%.128s)",
                namepart,
                verb,
                conn_get_dndstr(dest_c,0));
        message_send_text(c,message_type_info,c,msgtemp);
    }
    else
        if (conn_get_awaystr(dest_c))
        {
            sprintf(msgtemp,"%s away (%.128s)",
                    namepart,
                    conn_get_awaystr(dest_c));
            message_send_text(c,message_type_info,c,msgtemp);
        }
}


static void user_timer_cb(t_connection * c, time_t now, t_timer_data str)
{
    if (!c)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
        return;
    }
    if (!str.p)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL str");
        return;
    }

    if (now!=(time_t)0) /* zero means user logged out before expiration */
        message_send_text(c,message_type_info,c,(const char*)str.p);
    xfree(str.p);
}

typedef int (* t_command)(t_connection * c, char const * text);

typedef struct {
    const char * command_string;
    t_command    command_handler;
} t_command_table_row;

static int command_set_flags(t_connection * c); // [Omega]
// command handler prototypes
static int _handle_clan_command(t_connection * c, char const * text);
static int _handle_admin_command(t_connection * c, char const * text);
static int _handle_aop_command(t_connection * c, char const * text);
static int _handle_op_command(t_connection * c, char const * text);
static int _handle_tmpop_command(t_connection * c, char const * text);
static int _handle_deop_command(t_connection * c, char const * text);
static int _handle_voice_command(t_connection * c, char const * text);
static int _handle_devoice_command(t_connection * c, char const * text);
static int _handle_vop_command(t_connection * c, char const * text);
static int _handle_friends_command(t_connection * c, char const * text);
static int _handle_me_command(t_connection * c, char const * text);
static int _handle_whisper_command(t_connection * c, char const * text);
static int _handle_status_command(t_connection * c, char const * text);
static int _handle_who_command(t_connection * c, char const * text);
static int _handle_whois_command(t_connection * c, char const * text);
static int _handle_whoami_command(t_connection * c, char const * text);
static int _handle_announce_command(t_connection * c, char const * text);
static int _handle_beep_command(t_connection * c, char const * text);
static int _handle_nobeep_command(t_connection * c, char const * text);
static int _handle_version_command(t_connection * c, char const * text);
static int _handle_copyright_command(t_connection * c, char const * text);
static int _handle_uptime_command(t_connection * c, char const * text);
static int _handle_stats_command(t_connection * c, char const * text);
static int _handle_time_command(t_connection * c, char const * text);
static int _handle_channel_command(t_connection * c, char const * text);
static int _handle_rejoin_command(t_connection * c, char const * text);
static int _handle_away_command(t_connection * c, char const * text);
static int _handle_dnd_command(t_connection * c, char const * text);
static int _handle_squelch_command(t_connection * c, char const * text);
static int _handle_unsquelch_command(t_connection * c, char const * text);
//static int _handle_designate_command(t_connection * c, char const * text); Obsolete function [Omega]
//static int _handle_resign_command(t_connection * c, char const * text); Obsolete function [Omega]
static int _handle_kick_command(t_connection * c, char const * text);
static int _handle_ban_command(t_connection * c, char const * text);
static int _handle_unban_command(t_connection * c, char const * text);
static int _handle_reply_command(t_connection * c, char const * text);
static int _handle_realmann_command(t_connection * c, char const * text);
static int _handle_watch_command(t_connection * c, char const * text);
static int _handle_unwatch_command(t_connection * c, char const * text);
static int _handle_watchall_command(t_connection * c, char const * text);
static int _handle_unwatchall_command(t_connection * c, char const * text);
static int _handle_lusers_command(t_connection * c, char const * text);
static int _handle_news_command(t_connection * c, char const * text);
static int _handle_games_command(t_connection * c, char const * text);
static int _handle_channels_command(t_connection * c, char const * text);
static int _handle_addacct_command(t_connection * c, char const * text);
static int _handle_chpass_command(t_connection * c, char const * text);
static int _handle_connections_command(t_connection * c, char const * text);
static int _handle_finger_command(t_connection * c, char const * text);
static int _handle_operator_command(t_connection * c, char const * text);
static int _handle_admins_command(t_connection * c, char const * text);
static int _handle_quit_command(t_connection * c, char const * text);
static int _handle_kill_command(t_connection * c, char const * text);
static int _handle_killsession_command(t_connection * c, char const * text);
static int _handle_gameinfo_command(t_connection * c, char const * text);
static int _handle_ladderactivate_command(t_connection * c, char const * text);
static int _handle_rehash_command(t_connection * c, char const * text);
//static int _handle_rank_all_accounts_command(t_connection * c, char const * text);
static int _handle_shutdown_command(t_connection * c, char const * text);
static int _handle_ladderinfo_command(t_connection * c, char const * text);
static int _handle_timer_command(t_connection * c, char const * text);
static int _handle_serverban_command(t_connection * c, char const * text);
static int _handle_netinfo_command(t_connection * c, char const * text);
static int _handle_quota_command(t_connection * c, char const * text);
static int _handle_lockacct_command(t_connection * c, char const * text);
static int _handle_unlockacct_command(t_connection * c, char const * text);
static int _handle_flag_command(t_connection * c, char const * text);
static int _handle_tag_command(t_connection * c, char const * text);
//static int _handle_ipban_command(t_connection * c, char const * text); Redirected to handle_ipban_command() in ipban.c [Omega]
static int _handle_set_command(t_connection * c, char const * text);
static int _handle_motd_command(t_connection * c, char const * text);
static int _handle_ping_command(t_connection * c, char const * text);
static int _handle_commandgroups_command(t_connection * c, char const * text);
static int _handle_topic_command(t_connection * c, char const * text);
static int _handle_moderate_command(t_connection * c, char const * text);
static int _handle_clearstats_command(t_connection * c, char const * text);
static int _handle_icon_command(t_connection * c, char const * text);
static int _handle_lgame_command(t_connection * c, char const * text);
static int _handle_lwith_command(t_connection * c, char const *text);
static int _handle_iconadmin_command(t_connection * c, char const * text);
static int _handle_icondel_command(t_connection * c, char const * text);
static int _handle_clearstatsadmin_command(t_connection * c, char const * text);
static int _handle_teamset_command(t_connection * c, char const *text);
static int _handle_teamcheck_command(t_connection * c, char const *text);
static int _handle_imhackuser_command(t_connection * c, char const *text);

static const t_command_table_row standard_command_table[] =
    {
        { "/icon"		, _handle_icon_command },
        { "/lgame"			, _handle_lgame_command },
        { "/lwith"			, _handle_lwith_command },
        { "/iconadmin"			, _handle_iconadmin_command },
        { "/icondel"			, _handle_icondel_command },
        { "/clearstatsadmin"			, _handle_clearstatsadmin_command },
        { "/teamset"			, _handle_teamset_command },
        { "/teamcheck"			, _handle_teamcheck_command },
        { "/imhackuser"			, _handle_imhackuser_command },

        { "/clan"		, _handle_clan_command },
        { "/c"			, _handle_clan_command },
        { "/admin"		, _handle_admin_command },
        { "/f"                  , _handle_friends_command },
        { "/friends"            , _handle_friends_command },
        { "/me"                 , _handle_me_command },
        { "/msg"                , _handle_whisper_command },
        { "/whisper"            , _handle_whisper_command },
        { "/w"                  , _handle_whisper_command },
        { "/m"                  , _handle_whisper_command },
        { "/status"             , _handle_status_command },
        { "/users"              , _handle_status_command },
        { "/who"                , _handle_who_command },
        { "/whois"              , _handle_whois_command },
        { "/whereis"            , _handle_whois_command },
        { "/where"              , _handle_whois_command },
        { "/whoami"             , _handle_whoami_command },
        { "/announce"           , _handle_announce_command },
        { "/beep"               , _handle_beep_command },
        { "/nobeep"             , _handle_nobeep_command },
        { "/version"            , _handle_version_command },
        { "/copyright"          , _handle_copyright_command },
        { "/warrenty"           , _handle_copyright_command },
        { "/license"            , _handle_copyright_command },
        { "/uptime"             , _handle_uptime_command },
        { "/stats"              , _handle_stats_command },
        { "/astat"              , _handle_stats_command },
        { "/time"               , _handle_time_command },
        { "/channel"            , _handle_channel_command },
        { "/j"		            , _handle_channel_command },
        { "/join"               , _handle_channel_command },
        { "/rejoin"             , _handle_rejoin_command },
        { "/away"               , _handle_away_command },
        { "/dnd"                , _handle_dnd_command },
        { "/ignore"             , _handle_squelch_command },
        { "/squelch"            , _handle_squelch_command },
        { "/unignore"           , _handle_unsquelch_command },
        { "/unsquelch"          , _handle_unsquelch_command },
        //	{ "/designate"          , _handle_designate_command }, Obsotele command [Omega]
        //	{ "/resign"             , _handle_resign_command }, Obsolete command [Omega]
        { "/kick"               , _handle_kick_command },
        { "/ban"                , _handle_ban_command },
        { "/unban"              , _handle_unban_command },

        { NULL                  , NULL }

    };

static const t_command_table_row extended_command_table[] =
    {
        { "/ann"                , _handle_announce_command },
        { "/r"                  , _handle_reply_command },
        { "/reply"              , _handle_reply_command },
        { "/ㄱ"					, _handle_reply_command },
        { "/realmann"           , _handle_realmann_command },
        { "/watch"              , _handle_watch_command },
        { "/unwatch"            , _handle_unwatch_command },
        { "/watchall"           , _handle_watchall_command },
        { "/unwatchall"         , _handle_unwatchall_command },
        { "/lusers"             , _handle_lusers_command },
        { "/news"               , _handle_news_command },
        { "/games"              , _handle_games_command },
        { "/channels"           , _handle_channels_command },
        { "/chs"                , _handle_channels_command },
        { "/addacct"            , _handle_addacct_command },
        { "/chpass"             , _handle_chpass_command },
        { "/connections"        , _handle_connections_command },
        { "/con"                , _handle_connections_command },
        { "/finger"             , _handle_finger_command },
        { "/operator"           , _handle_operator_command },
        { "/aop"		, _handle_aop_command },
        { "/op"           	, _handle_op_command },
        { "/tmpop"           	, _handle_tmpop_command },
        { "/deop"           	, _handle_deop_command },
        { "/voice"		, _handle_voice_command },
        { "/devoice"		, _handle_devoice_command },
        { "/vop"		, _handle_vop_command },
        { "/admins"             , _handle_admins_command },
        { "/logout"             , _handle_quit_command },
        { "/quit"               , _handle_quit_command },
        { "/exit"               , _handle_quit_command },
        { "/kill"               , _handle_kill_command },
        { "/killsession"        , _handle_killsession_command },
        { "/gameinfo"           , _handle_gameinfo_command },
        { "/ladderactivate"     , _handle_ladderactivate_command },
        { "/rehash"             , _handle_rehash_command },
        //	{ "/rank_all_accounts"  , _handle_rank_all_accounts_command },
        { "/shutdown"           , _handle_shutdown_command },
        { "/ladderinfo"         , _handle_ladderinfo_command },
        { "/timer"              , _handle_timer_command },
        { "/serverban"          , _handle_serverban_command },
        { "/netinfo"            , _handle_netinfo_command },
        { "/quota"              , _handle_quota_command },
        { "/lockacct"           , _handle_lockacct_command },
        { "/unlockacct"         , _handle_unlockacct_command },
        { "/flag"               , _handle_flag_command },
        { "/tag"                , _handle_tag_command },
        { "/help"               , handle_help_command },
        { "/mail"               , handle_mail_command },
        { "/ipban"              , handle_ipban_command }, // in ipban.c
        { "/set"                , _handle_set_command },
        { "/motd"               , _handle_motd_command },
        { "/latency"            , _handle_ping_command },
        { "/ping"               , _handle_ping_command },
        { "/p"                  , _handle_ping_command },
        { "/commandgroups"	, _handle_commandgroups_command },
        { "/cg"			, _handle_commandgroups_command },
        { "/topic"		, _handle_topic_command },
        { "/moderate"		, _handle_moderate_command },
        { "/clearstats"		, _handle_clearstats_command },

        { NULL                  , NULL }

    };

char const * skip_command(char const * org_text)
{
    unsigned int i;
    char * text = (char *)org_text;
    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    if (text[i]!='\0') text[i++]='\0';             /* \0-terminate command */
    for (; text[i]==' '; i++);
    return &text[i];
}

static int __INIT=1;

unordered_map< string	,t_command> _command;

extern int handle_command(t_connection * c,  char const * text)
{
	if(__INIT)
	{
	    t_command_table_row const *p;
		__INIT=0;
	    for (p = standard_command_table; p->command_string != NULL; p++)
		{
			if(p->command_string==0||p->command_handler==0)continue;
			_command.insert(make_pair(p->command_string,p->command_handler));
		}
	    for (p = extended_command_table; p->command_string != NULL; p++)
		{
			if(p->command_string==0||p->command_handler==0)continue;
			_command.insert(make_pair(p->command_string,p->command_handler));
		}
	}
	int i;
	for(i=0;i<=80;i++)
		if(text[i]==' '||text[i]=='\t'||text[i]==0)
			break;
	string com(text,text+i);
	to_lower(com);
	BOOST_AUTO(commandIt, _command.find(com));
	if(commandIt!=_command.end())
	{
		if (!(command_get_group(com.c_str())))
		{
			message_send_text(c,message_type_error,c,"This command has been deactivated");
			return 0;
		}
		if (!((command_get_group(com.c_str()) & account_get_command_groups(conn_get_account(c)))))
		{
			message_send_text(c,message_type_error,c,"This command is reserved for admins.");
			return 0;
		}
		commandIt->second(c,text);
		return 0;
	}

    if (strlen(text)>=2 && strncmp(text,"//",2)==0)
    {
        handle_alias_command(c,text);
        return 0;
    }

    message_send_text(c,message_type_error,c,"Unknown command.");
    eventlog(eventlog_level_debug,__FUNCTION__,"got unknown command \"%s\"",text);
    return 0;
}

// +++++++++++++++++++++++++++++++++ command implementations +++++++++++++++++++++++++++++++++++++++

static int _handle_clan_command(t_connection * c, char const * text)
{
	t_account * acc=0;
	t_clanmember * member=0;
	t_clan * clan=0;

    text = skip_command(text);

	message_send_text(c,message_type_info,c,"[테스트 중인 기능입니다. 추후 클랜리셋 됩니다]");
    if ( text[0] == '\0' )
    {
        message_send_text(c,message_type_info,c,"usage:");
        message_send_text(c,message_type_info,c,"/clan public  /clan pub");
		message_send_text(c,message_type_info,c,"모두 클랜 채널에 들어가기");
        message_send_text(c,message_type_info,c,"/clan private  /clan priv");
		message_send_text(c,message_type_info,c,"클랜원만 클랜 채널에 들어가기");
        message_send_text(c,message_type_info,c,"/clan motd MESSAGE");
		message_send_text(c,message_type_info,c,"클랜 인사말 설정하기");
		message_send_text(c,message_type_info,c,"/clan create <클랜닉> <클랜채널> <ID-1> <ID-2> <ID-3> <ID-4>");
		message_send_text(c,message_type_info,c,"클랜만들기");
		message_send_text(c,message_type_info,c," - 클랜닉 : 영문과 숫자 조합 4글자");
		message_send_text(c,message_type_info,c," - 클랜채널 : 클랜의 채널 'cl-' 생략");
		message_send_text(c,message_type_info,c," - ID-1,2,3,4 : 클랜가입에 동의한 4명의 ID");
		message_send_text(c,message_type_info,c,"/c check <클랜닉>");
		message_send_text(c,message_type_info,c,"해당 클랜닉으로 클랜 생성 가능한지 확인하기");
		message_send_text(c,message_type_info,c,"/c join <클랜닉>");
		message_send_text(c,message_type_info,c,"클랜가입에 동의 하기");
		message_send_text(c,message_type_info,c,"/c remove <username>");
		message_send_text(c,message_type_info,c,"길드원 삭제하기");
		message_send_text(c,message_type_info,c,"/c add <username>");
		message_send_text(c,message_type_info,c,"길드원 추가하기, 반드시 클랜가입동의가 필요함");
		message_send_text(c,message_type_info,c,"/c list");
		message_send_text(c,message_type_info,c,"클랜원 목록보기");
		message_send_text(c,message_type_info,c,"/c m <할말>");
		message_send_text(c,message_type_info,c,"클랜원들에게 말하기");
		message_send_text(c,message_type_info,c,"/c newmaster <ID>");
		message_send_text(c,message_type_info,c,"클랜장을 다른사람에게 넘기기");
		message_send_text(c,message_type_info,c,"");
		message_send_text(c,message_type_info,c,"클랜생성시 주어지는 채널 : cl-<클랜채널>");
        return 0;
    }

	((acc = conn_get_account(c)) && (member = account_get_clanmember(acc)) && (clan = clanmember_get_clan(member)));


            if (strstart(text,"public")==0 || strstart(text,"pub")==0) {
		if(!clan)
		{
			message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		if (clanmember_get_status(member)<CLAN_CHIEFTAIN)
			message_send_text(c,message_type_error,c,"You are not a ClanMaster!");
                if(clan_get_channel_type(clan)!=0)
                {
                    clan_set_channel_type(clan,0);
                    message_send_text(c,message_type_info,c,"Clan channel is opened up!");
                }
                else
                    message_send_text(c,message_type_error,c,"Clan channel has already been opened up!");
            }
	else if (strstart(text,"private")==0 || strstart(text,"priv")==0) {
		if(!clan)
		{
			message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		if (clanmember_get_status(member)<CLAN_CHIEFTAIN)
			message_send_text(c,message_type_error,c,"You are not a ClanMaster!");
                    if(clan_get_channel_type(clan)!=1)
                    {
                        clan_set_channel_type(clan,1);
                        message_send_text(c,message_type_info,c,"Clan channel is closed!");
                    }
                    else
                        message_send_text(c,message_type_error,c,"Clan channel has already been closed!");
                }
	else if (strstart(text,"motd")==0)
	{
                        const char * msg=skip_command(text);
		if(!clan)
		{
			message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		if (clanmember_get_status(member)<CLAN_CHIEFTAIN)
			message_send_text(c,message_type_error,c,"You are not a ClanMaster!");
                        if(msg[0]=='\0')
                        {
                            message_send_text(c,message_type_info,c,"usage:");
                            message_send_text(c,message_type_info,c,"/clan motd MESSAGE");
                            message_send_text(c,message_type_info,c,"Update the clan message of the day to MESSAGE.");
                        }
                        else
                        {
                            clan_set_motd(clan, msg);
                            message_send_text(c,message_type_info,c,"Clan message of day is updated!");
                        }
                    }
	else if (strstart(text,"add")==0 || strstart(text,"a")==0)
	{
		t_packet 	* rpacket;
		t_connection 	* dest_c;
		t_account    	* friend_acc;
		t_server_friendslistreply_status status;
		t_game * game;
		t_channel * channel;
		char stat;
		t_clanmember *member;

		if(!clan)
		{
			message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		if (clanmember_get_status(member)<CLAN_CHIEFTAIN)
			message_send_text(c,message_type_error,c,"You are not a ClanMaster!");
		text = skip_command(text);

		if (text[0] == '\0') {
			message_send_text(c,message_type_info,c,"usage: /c add <username>");
			return 0;
        }

		if (!(friend_acc = accountlist_find_account(text))) {
			message_send_text(c,message_type_info,c,"That user does not exist.");
			return 0;
		}
		if (clan_get_member_count(clan) >= prefs_get_clan_max_members()) {
			sprintf(msgtemp, "You can only have a maximum of %d Clan members.", prefs_get_max_friends());
			message_send_text(c,message_type_info,c,msgtemp);
			return 0;
		}
		if(acc==friend_acc)
		{
			message_send_text(c,message_type_info,c,"You can't add yourself to your Clan members list.");
			return 0;
		}
		if(account_get_clan(friend_acc))
		{
			sprintf(msgtemp, "%s has Clan members already!", text);
			message_send_text(c,message_type_info,c,msgtemp);
			return 0;
		}
		if(account_get_numattr(friend_acc,"BNET\\joinclan")!=clan_get_clantag(clan))
		{
			sprintf(msgtemp, "%s님이 동의하지않으셨습니다. (동의 방법 : /clan join 클랜닉)", text);
			message_send_text(c,message_type_info,c,msgtemp);
			return 0;
		}
		if(!(member = clan_add_member(clan, friend_acc, 1)))
		{
			message_send_text(c,message_type_error,c,"Server error.");
			return 0;
		}
		sprintf( msgtemp, "Added %s to your Clan members list.", text);
		message_send_text(c,message_type_info,c,msgtemp);
		dest_c = connlist_find_connection_by_account(friend_acc);
		if(dest_c!=NULL) {
			sprintf(msgtemp,"%s added you to his/her Clan members  list.",conn_get_username(c));
			message_send_text(dest_c,message_type_info,dest_c,msgtemp);
		}
//		clanlog(clan_get_clantag(clan),"MI",text,0);
	}
	else if (strstart(text,"newmaster")==0)
	{
		t_packet 	* rpacket;
		t_connection 	* dest_c;
		t_account    	* friend_acc;
		t_server_friendslistreply_status status;
		t_game * game;
		t_channel * channel;
		char stat;
		t_clanmember *member;

		if(!clan)
		{
			message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		if (clanmember_get_status(member)<CLAN_CHIEFTAIN)
		{
			message_send_text(c,message_type_error,c,"You are not a ClanMaster!");
			return 0;
		}
		text = skip_command(text);

		if (text[0] == '\0') {
			message_send_text(c,message_type_info,c,"usage: /c add <username>");
			return 0;
		}

		if (!(friend_acc = accountlist_find_account(text))) {
			message_send_text(c,message_type_info,c,"That user does not exist.");
			return 0;
		}
		if(acc==friend_acc)
		{
			message_send_text(c,message_type_info,c,"You can't choose yourself");
			return 0;
		}
		if(account_get_clan(friend_acc))
		{
			sprintf(msgtemp, "%s has Clan members already!", text);
			message_send_text(c,message_type_info,c,msgtemp);
			return 0;
		}
		if(clan_get_clantag(clanmember_get_clan(account_get_clanmember(friend_acc)))
				!=clan_get_clantag(clanmember_get_clan(account_get_clanmember(acc))))
		{
			sprintf(msgtemp, "%s님은 다른 클랜입니다.", text);
			message_send_text(c,message_type_info,c,msgtemp);
			return 0;
		}
		clanmember_set_status(account_get_clanmember(acc),CLAN_PEON);
		clanmember_set_status(account_get_clanmember(friend_acc),CLAN_CHIEFTAIN);
		sprintf( msgtemp, " %s 님이 새로 길드마스터가 되셨습니다", text);
		message_send_text(c,message_type_info,c,msgtemp);
		dest_c = connlist_find_connection_by_account(friend_acc);
		if(dest_c!=NULL) {
			sprintf(msgtemp,"%s 님이 귀하를 길드마스터로 추대하였습니다",conn_get_username(c));
			message_send_text(dest_c,message_type_info,dest_c,msgtemp);
		}
		//clanlog(clan_get_clantag(clan),"MU",conn_get_username(c),0);
		//clanlog(clan_get_clantag(clan),"MU",text,1);
	}
	else if (strstart(text,"remove")==0 || strstart(text,"r")==0)
	{
		t_packet 	* rpacket;
		t_connection 	* dest_c;
		t_account    	* friend_acc;
		t_server_friendslistreply_status status;
		t_game * game;
		t_channel * channel;
		char stat;
		t_clanmember *member;

		if(!clan)
		{
			message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		if (clanmember_get_status(member)<CLAN_CHIEFTAIN)
			message_send_text(c,message_type_error,c,"You are not a ClanMaster!");
		text = skip_command(text);

		if (text[0] == '\0') {
			message_send_text(c,message_type_info,c,"usage: /c remove <username>");
			return 0;
		}

		if (!(friend_acc = accountlist_find_account(text))) {
			message_send_text(c,message_type_info,c,"That user does not exist.");
			return 0;
		}
		if(acc==friend_acc)
		{
			message_send_text(c,message_type_info,c,"You can't remove yourself to your Clan members list.");
			return 0;
		}
		if(!account_get_clan(friend_acc))
		{
			sprintf(msgtemp, "%s is not Clan members!", text);
			message_send_text(c,message_type_info,c,msgtemp);
			return 0;
		}
		if(clan_get_clantag(account_get_clan(friend_acc))!=clan_get_clantag(clan))
		{
			sprintf(msgtemp, "%s is not Clan members!", text);
			message_send_text(c,message_type_info,c,msgtemp);
			return 0;
		}
		if(!clan_remove_member(clan, account_get_clanmember(friend_acc)))
		{
			message_send_text(c,message_type_error,c,"Server error.");
			return 0;
		}
		sprintf( msgtemp, "Deleted %s to your Clan members list.", text);
		message_send_text(c,message_type_info,c,msgtemp);
		dest_c = connlist_find_connection_by_account(friend_acc);
		if(dest_c!=NULL) {
			sprintf(msgtemp,"%s deleted you to his/her Clan members  list.",conn_get_username(c));
			message_send_text(dest_c,message_type_info,dest_c,msgtemp);
		}
		//clanlog(clan_get_clantag(clan),"MD",text,0);
	}
	else if (strstart(text,"msg")==0 || strstart(text,"w")==0 || strstart(text,"whisper")==0 || strstart(text,"m")==0)
	{
		char const *msg;
		int cnt = 0;
		t_connection * dest_c;
		t_elem  * curr;
		t_friend * fr;
		t_list  * flist;
		t_account * memberacc;

		if(!clan)
		{
			message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		msg = skip_command(text);
		/* if the message test is empty then ignore command */
		if (msg[0]=='\0') {
			message_send_text(c,message_type_info,c,"Did not message any friends. Type some text next time.");
			return 0;
    }

		LIST_TRAVERSE(clan_get_members(clan), curr)
		{
			if (!(member = (t_clanmember*)elem_get_data(curr))) {
				eventlog(eventlog_level_error,__FUNCTION__,"found NULL entry in list");
				continue;
			}
			if (!(memberacc = clanmember_get_account(member)))
			{
				eventlog(eventlog_level_error,__FUNCTION__,"member has NULL account");
				continue;
			}
			dest_c = connlist_find_connection_by_account(memberacc);
			if (!dest_c) continue;
			if(conn_get_dndstr(dest_c,1))
			{
				sprintf(msgtemp,"%s is refusing messages (%.128s)",
						account_get_name(memberacc),
						conn_get_dndstr(dest_c,1));
				message_send_text(c,message_type_info,c,msgtemp);
				continue;
			}
			message_send_text(dest_c,message_type_whisper,c,msg);
			cnt++;
		}
		if(cnt)
			message_send_text(c,message_type_friendwhisperack,c,msg);
    else
			message_send_text(c,message_type_info,c,"All your Clan members are offline.");
		return 0;
	}
	else if (strstart(text,"list")==0 || strstart(text,"l")==0) {
		char const * friend_;
		char status[128];
		char software[64];
		char msgtemp[MAX_MESSAGE_LEN];
		t_connection * dest_c;
		t_account * friend_acc;
		t_game const * game;
		t_channel const * channel;
		t_friend * fr;
		t_list  * flist;
		int num;
		unsigned int uid;
		t_elem  * curr;
		int i=-1;

		if(!clan)
		{
        message_send_text(c,message_type_error,c,"You are not in a clan!");
			return 0;
		}
		message_send_text(c,message_type_info,c,"Clan members List");
		message_send_text(c,message_type_info,c,"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
		LIST_TRAVERSE(clan_get_members(clan), curr)
		{
			i++;
			if (!(member = (t_clanmember*)elem_get_data(curr))) {
				eventlog(eventlog_level_error,__FUNCTION__,"found NULL entry in list");
				continue;
			}
			if (!(friend_acc = clanmember_get_account(member)))
			{
				eventlog(eventlog_level_error,__FUNCTION__,"member has NULL account");
				continue;
			}
			software[0]='\0';
			if (!(dest_c = connlist_find_connection_by_account(friend_acc)))
				sprintf(status, ", offline");
			else {
				sprintf(software," using %s", clienttag_get_title(conn_get_clienttag(dest_c)));

				if ((game = conn_get_game(dest_c)))
					sprintf(status, ", in game \"%.64s\"", game_get_name(game));
				else if ((channel = conn_get_channel(dest_c))) {
					if(strcasecmp(channel_get_name(channel),"Arranged Teams")==0)
						sprintf(status, ", in game AT Preparation");
					else
						sprintf(status, ", in channel \"%.64s\",", channel_get_name(channel));
				}
				else
					sprintf(status, ", is in AT Preparation");
			}

			friend_=account_get_name(friend_acc);
			if (software[0]) sprintf(msgtemp, "%d: %.16s%.128s, %.64s", i+1,  friend_, status,software);
			else sprintf(msgtemp, "%d: %.16s%.128s", i+1, friend_, status);
			message_send_text(c,message_type_info,c,msgtemp);
		}
		message_send_text(c,message_type_info,c,"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
		return 0;
	}
	else if (acc &&(strstart(text,"join")==0 || strstart(text,"j")==0))
	{
		t_packet 	* rpacket;
		t_connection 	* dest_c;
		t_account    	* friend_acc;
		t_server_friendslistreply_status status;
		t_game * game;
		t_channel * channel;
		char stat;
		t_clanmember *member;
		int i,j;
		char tag[4];

		text = skip_command(text);

		if (text[0] == '\0') {
			j=account_get_numattr(acc,"BNET\\joinclan");
			if(j)
			{
				sprintf(msgtemp,"현재 가입 동의한 클랜닉 : '%c$c$c$c'",(j>>24)&0xff,(j>>16)&0xff,(j>>8)&0xff,(j)&0xff);
				message_send_text(c,message_type_info,c,"usage: /c join <클랜닉>");
			}
			message_send_text(c,message_type_info,c,"usage: /c join <클랜닉>");
			return 0;
		}
		if(strlen(text)!=4)
		{
			message_send_text(c,message_type_info,c,"클랜닉은 영문자와 숫자로 4글자입니다");
			return 0;
		}
		for(i=0;i<4;i++)
		{
			tag[i]=text[i];
			j=0;
			if(tag[i]>='a'&&tag[i]<='z')
			{
				j=1;
			}
			if(!j&&tag[i]>='A'&&tag[i]<='Z')
				j=1;
			if(!j&&tag[i]>='0'&&tag[i]<='9')
				j=1;
			if(j==0)break;
		}
		if(i!=4)
		{
			message_send_text(c,message_type_info,c,"클랜닉은 영문자와 숫자로 4글자입니다");
			return 0;
		}
		account_set_numattr(acc,"BNET\\joinclan",str_to_clantag(tag));
		message_send_text(c,message_type_info,c,"클랜초대를 받을 준비가 되었습니다");
	}
	else if (acc &&(strstart(text,"create")==0 || strstart(text,"c")==0))
	{
		t_packet 	* rpacket;
		t_connection 	* dest_c;
		t_account    	* friend_acc,*account;
		t_server_friendslistreply_status status;
		t_game * game;
		t_channel * channel;
		char stat;
		t_clanmember *member;
		int i,j;
		char const *tag,*clanname, *mem[4];
		int created, clantag;
		t_clan *clan;
		const int CLANMEM=4;

		tag = skip_command(text);
		clanname = skip_command(tag);
		mem[0]=skip_command(clanname);
		mem[1]=skip_command(mem[0]);
		mem[2]=skip_command(mem[1]);
		mem[3]=skip_command(mem[2]);



		if (tag[0] == '\0' || clanname[0] == '\0')
		{
			message_send_text(c,message_type_info,c,"usage: /c create <클랜닉> <클랜채널> <ID-1> <ID-2> <ID-3> <ID-4>");
			return 0;
		}
		for(i=0;i<CLANMEM;i++)
		{
			if(mem[i][0] ==0)
			{
				message_send_text(c,message_type_info,c,"usage: /c create <클랜닉> <클랜채널> <ID-1> <ID-2> <ID-3> <ID-4>");
				return 0;
			}
		}
		if(strlen(tag)!=4)
		{
			message_send_text(c,message_type_error,c,"클랜닉은 영문자와 숫자로 4글자입니다");
			return 0;
		}
		for(i=0;i<4;i++)
		{
			j=0;
			if(tag[i]>='a'&&tag[i]<='z')
				j=1;
			if(!j&&tag[i]>='A'&&tag[i]<='Z')
				j=1;
			if(!j&&tag[i]>='0'&&tag[i]<='9')
				j=1;
			if(j==0)break;
		}
		if(i!=4)
		{
			message_send_text(c,message_type_error,c,"클랜닉은 영문자와 숫자로 4글자입니다");
			return 0;
		}
		clantag=str_to_clantag(tag);
		if(clanlist_find_clan_by_clantag(clantag)!=NULL)
		{
			message_send_text(c,message_type_error,c,"이미 존재하는 클랜닉입니다.");
			return 0;
		}
		if (clanlist_find_clan_by_clanname(clanname)!=NULL)
		{
			message_send_text(c,message_type_error,c,"이미 존재하는 클랜채널입니다.");
			return 0;
		}
		if ((account = conn_get_account(c)) && (account_get_clan(account) != NULL))
		{
			message_send_text(c,message_type_error,c,"현재 클랜에 소속 중입니다.");
			return 0;
		}
		for (i=0;i<CLANMEM;i++)
		{
			if (!(friend_acc = accountlist_find_account(mem[i]))) {
				sprintf(msgtemp,"%d번쨰 입력한 %s 유저가 존재하지 않습니다",i+1,mem[i]);
				message_send_text(c,message_type_error,c,msgtemp);
				return 0;
			}
			if(conn_get_account(c)==friend_acc)
			{
				message_send_text(c,message_type_error,c,"자신은 클랜 멤버로 등록할 수 없습니다");
				return 0;
			}
			if(account_get_numattr(friend_acc,"BNET\\joinclan")!=clantag)
			{
				sprintf(msgtemp, "%s님이 동의하지않으셨습니다. (동의 방법 : /clan join 클랜닉)", mem[i]);
				message_send_text(c,message_type_error,c,msgtemp);
				return 0;
			}
			for(j=i+1;j<CLANMEM;j++)
			{
				if(0==strcasecmp(mem[i],mem[j]))
				{
					message_send_text(c,message_type_error,c,"중복된 ID가 존재합니다");
					return 0;
				}
			}
		}
		if(clanlist_find_clan_by_clantag(clantag)!=NULL)
		{
			message_send_text(c,message_type_error,c,"이미 존재하는 클랜닉입니다.");
			return 0;
		}
		if (!(clan = clan_create(account, clantag, clanname, NULL))) {
			message_send_text(c,message_type_error,c,"클랜 생성 중 에러 발생(1)");
			return 0;
		}
		if (clanlist_add_clan(clan)==-1) {
			message_send_text(c,message_type_error,c,"클랜 생성 중 에러 발생(2)");
			return 0;
		}
		clan_set_created(clan,120);
		//clanlog(clan_get_clantag(clan),"CI",clanname,0);
		//clanlog(clan_get_clantag(clan),"MI",account_get_name(acc),1);
		for (i=0;i<CLANMEM;i++)
		{
			clan_add_member(clan, accountlist_find_account(mem[i]), CLAN_NEW);
			//clanlog(clan_get_clantag(clan),"MI",mem[i],0);
		}
		message_send_text(c,message_type_info,c,"클랜이 생성 되었습니다.");
		return 0;
	}
	else if (acc &&(strstart(text,"check")==0))
	{
		t_packet 	* rpacket;
		t_connection 	* dest_c;
		t_account    	* friend_acc,*account;
		t_server_friendslistreply_status status;
		t_game * game;
		t_channel * channel;
		char stat;
		t_clanmember *member;
		int i,j;
		char const *tag;
		int created, clantag;
		t_clan *clan;

		tag = skip_command(text);

		if (tag[0] == '\0')
		{
			message_send_text(c,message_type_info,c,"usage: /c check <클랜닉>");
			return 0;
		}
		if(strlen(tag)!=4)
		{
			message_send_text(c,message_type_error,c,"클랜닉은 영문자와 숫자로 4글자입니다");
			return 0;
		}
		for(i=0;i<4;i++)
		{
			j=0;
			if(tag[i]>='a'&&tag[i]<='z')
				j=1;
			if(!j&&tag[i]>='A'&&tag[i]<='Z')
				j=1;
			if(!j&&tag[i]>='0'&&tag[i]<='9')
				j=1;
			if(j==0)break;
		}
		if(i!=4)
		{
			message_send_text(c,message_type_error,c,"클랜닉은 영문자와 숫자로 4글자입니다");
			return 0;
		}
		clantag=str_to_clantag(tag);
		if(clanlist_find_clan_by_clantag(clantag)!=NULL)
		{
			message_send_text(c,message_type_error,c,"이미 존재하는 클랜닉입니다.");
			return 0;
		}
		message_send_text(c,message_type_info,c,"해당 닉으로 클랜이 생성가능합니다.");
		return 0;
	}
	else
	{
		message_send_text(c,message_type_info,c,"usage:");
		message_send_text(c,message_type_info,c,"/clan public  /clan pub");
		message_send_text(c,message_type_info,c,"모두 클랜 채널에 들어가기");
		message_send_text(c,message_type_info,c,"/clan private  /clan priv");
		message_send_text(c,message_type_info,c,"클랜원만 클랜 채널에 들어가기");
		message_send_text(c,message_type_info,c,"/clan motd MESSAGE");
		message_send_text(c,message_type_info,c,"클랜 인사말 설정하기");
		message_send_text(c,message_type_info,c,"/clan create <클랜닉> <클랜채널> <ID-1> <ID-2> <ID-3> <ID-4>");
		message_send_text(c,message_type_info,c,"클랜만들기");
		message_send_text(c,message_type_info,c," - 클랜닉 : 영문과 숫자 조합 4글자");
		message_send_text(c,message_type_info,c," - 클랜채널 : 클랜의 채널 'cl-' 생략");
		message_send_text(c,message_type_info,c," - ID-1,2,3,4 : 클랜가입에 동의한 4명의 ID");
		message_send_text(c,message_type_info,c,"/c check <클랜닉>");
		message_send_text(c,message_type_info,c,"해당 클랜닉으로 클랜 생성 가능한지 확인하기");
		message_send_text(c,message_type_info,c,"/c join <클랜닉>");
		message_send_text(c,message_type_info,c,"클랜가입에 동의 하기");
		message_send_text(c,message_type_info,c,"/c remove <username>");
		message_send_text(c,message_type_info,c,"길드원 삭제하기");
		message_send_text(c,message_type_info,c,"/c add <username>");
		message_send_text(c,message_type_info,c,"길드원 추가하기, 반드시 클랜가입동의가 필요함");
		message_send_text(c,message_type_info,c,"/c list");
		message_send_text(c,message_type_info,c,"클랜원 목록보기");
		message_send_text(c,message_type_info,c,"/c m <할말>");
		message_send_text(c,message_type_info,c,"클랜원들에게 말하기");
		message_send_text(c,message_type_info,c,"/c newmaster <ID>");
		message_send_text(c,message_type_info,c,"클랜장을 다른사람에게 넘기기");
		message_send_text(c,message_type_info,c,"");
		message_send_text(c,message_type_info,c,"클랜생성시 주어지는 채널 : cl-<클랜채널>");
		return 0;
	}
    return 0;
}

static int command_set_flags(t_connection * c)
{
    return channel_set_userflags(c);
}

static int _handle_admin_command(t_connection * c, char const * text)
{
    char const *	username;
    char		command;
    t_account *		acc;
    t_connection *	dst_c;
    int			changed=0;

    text = skip_command(text);

    if ((text[0]=='\0') || ((text[0] != '+') && (text[0] != '-'))) {
        message_send_text(c,message_type_info,c,"usage: /admin +username to promote user to Server Admin.");
        message_send_text(c,message_type_info,c,"       /admin -username to demote user from Aerver Admin.");
        return -1;
    }

    command = text[0];
    username = &text[1];

    if(!*username) {
        message_send_text(c,message_type_info,c,"You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }
    dst_c = account_get_conn(acc);

    if (command == '+') {
        if (account_get_auth_admin(acc,NULL) == 1) {
            sprintf(msgtemp,"%s is already a Server Admin",username);
        } else {
            account_set_auth_admin(acc,NULL,1);
            sprintf(msgtemp,"%s has been promoted to a Server Admin",username);
            sprintf(msgtemp2,"%s has promoted you to a Server Admin",conn_get_loggeduser(c));
            changed = 1;
        }
    } else {
        if (account_get_auth_admin(acc,NULL) != 1)
            sprintf(msgtemp,"%s is no Server Admin, so you can't demote him",username);
        else {
            account_set_auth_admin(acc,NULL,0);
            sprintf(msgtemp,"%s has been demoted from a Server Admin",username);
            sprintf(msgtemp2,"%s has demoted you from a Server Admin",conn_get_loggeduser(c));
            changed = 1;
        }
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    command_set_flags(dst_c);
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
    return 0;
}

static int _handle_operator_command(t_connection * c, char const * text)
{
    char const *	username;
    char		command;
    t_account *		acc;
    t_connection *	dst_c;
    int			changed = 0;

    text = skip_command(text);

    if ((text[0]=='\0') || ((text[0] != '+') && (text[0] != '-'))) {
        message_send_text(c,message_type_info,c,"usage: /operator +username to promote user to Server Operator.");
        message_send_text(c,message_type_info,c,"       /operator -username to demote user from Server Operator.");
        return -1;
    }

    command = text[0];
    username = &text[1];

    if(!*username) {
        message_send_text(c,message_type_info,c,"You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }
    dst_c = account_get_conn(acc);

    if (command == '+') {
        if (account_get_auth_operator(acc,NULL) == 1)
            sprintf(msgtemp,"%s is already a Server Operator",username);
        else {
            account_set_auth_operator(acc,NULL,1);
            sprintf(msgtemp,"%s has been promoted to a Server Operator",username);
            sprintf(msgtemp2,"%s has promoted you to a Server Operator",conn_get_loggeduser(c));
            changed = 1;
        }
    } else {
        if (account_get_auth_operator(acc,NULL) != 1)
            sprintf(msgtemp,"%s is no Server Operator, so you can't demote him",username);
        else {
            account_set_auth_operator(acc,NULL,0);
            sprintf(msgtemp,"%s has been demoted from a Server Operator",username);
            sprintf(msgtemp2,"%s has promoted you to a Server Operator",conn_get_loggeduser(c));
            changed = 1;
        }
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    command_set_flags(dst_c);
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
    return 0;
}

static int _handle_aop_command(t_connection * c, char const * text)
{
    char const *	username;
    char const *	channel;
    t_account *		acc;
    t_connection *	dst_c;
    int			changed = 0;

    if (!(conn_get_channel(c)) || !(channel = channel_get_name(conn_get_channel(c)))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    if (account_is_operator_or_admin(conn_get_account(c),channel)<3) {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Admin to use this command.");
        return -1;
    }

    text = skip_command(text);

    if (!(username = &text[0])) {
        message_send_text(c, message_type_info, c, "You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }

    dst_c = account_get_conn(acc);

    if (account_is_operator_or_admin(acc,channel) >=2)
        sprintf(msgtemp,"%s is already a Channel Admin",username);
    else {
        account_set_auth_admin(acc,channel,1);
        sprintf(msgtemp,"%s has been promoted to a Channel Admin",username);
        sprintf(msgtemp2,"%s has promoted you to a Channel Admin for channel \"%s\"",conn_get_loggeduser(c),channel);
        changed = 1;
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    command_set_flags(dst_c);
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
    return 0;
}

static int _handle_vop_command(t_connection * c, char const * text)
{
    char const *	username;
    char const *	channel;
    t_account *		acc;
    t_connection *	dst_c;
    int			changed = 0;

    if (!(conn_get_channel(c)) || !(channel = channel_get_name(conn_get_channel(c)))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    if (account_is_operator_or_admin(conn_get_account(c),channel)<2) {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Admin to use this command.");
        return -1;
    }

    text = skip_command(text);

    if (!(username = &text[0])) {
        message_send_text(c, message_type_info, c, "You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }

    dst_c = account_get_conn(acc);

    if (account_get_auth_voice(acc,channel) == 1)
        sprintf(msgtemp,"%s is already on VOP list",username);
    else {
        account_set_auth_voice(acc,channel,1);
        sprintf(msgtemp,"%s has been added to the VOP list",username);
        sprintf(msgtemp2,"%s has added you to the VOP list of channel \"%s\"",conn_get_loggeduser(c),channel);
        changed = 1;
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    command_set_flags(dst_c);
    return 0;
}

static int _handle_voice_command(t_connection * c, char const * text)
{
    char const *	username;
    char const *	channel;
    t_account *		acc;
    t_connection *	dst_c;
    int			changed = 0;

    if (!(conn_get_channel(c)) || !(channel = channel_get_name(conn_get_channel(c)))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    if (2>(account_is_operator_or_admin(conn_get_account(c),channel_get_name(conn_get_channel(c))))) {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Operator to use this command.");
        return -1;
    }

    text = skip_command(text);

    if (!(username = &text[0])) {
        message_send_text(c, message_type_info, c, "You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }
    dst_c = account_get_conn(acc);
    if (account_get_auth_voice(acc,channel)==1)
        sprintf(msgtemp,"%s is already on VOP list, no need to Voice him", username);
    else
    {
        if ((!dst_c) || conn_get_channel(c)!=conn_get_channel(dst_c))
        {
            sprintf(msgtemp,"%s must be on the same channel to voice him",username);
        }
        else
        {
            if (channel_conn_has_tmpVOICE(conn_get_channel(c),dst_c))
                sprintf(msgtemp,"%s has already Voice in this channel",username);
            else {
                if (account_is_operator_or_admin(acc,channel))
                    sprintf(msgtemp,"%s allready is operator or admin, no need to voice him",username);
                else
                {
                    conn_set_tmpVOICE_channel(dst_c,channel);
                    sprintf(msgtemp,"%s has been granted Voice in this channel",username);
                    sprintf(msgtemp2,"%s has granted you Voice in this channel",conn_get_loggeduser(c));
                    changed = 1;
                }
            }
        }
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    command_set_flags(dst_c);
    return 0;
}

static int _handle_devoice_command(t_connection * c, char const * text)
{
    char const *	username;
    char const *	channel;
    t_account *		acc;
    t_connection *	dst_c;
    int			done = 0;
    int			changed = 0;

    if (!(conn_get_channel(c)) || !(channel = channel_get_name(conn_get_channel(c)))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    if ((account_is_operator_or_admin(conn_get_account(c),channel_get_name(conn_get_channel(c))))<2) {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Operator to use this command.");
        return -1;
    }

    text = skip_command(text);

    if (!(username = &text[0])) {
        message_send_text(c, message_type_info, c, "You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }
    dst_c = account_get_conn(acc);

    if (account_get_auth_voice(acc,channel)==1)
    {
//        if ((account_get_auth_admin(conn_get_account(c),channel)==1) || (account_get_auth_admin(conn_get_account(c),NULL)==1))
        if (1)
        {
            account_set_auth_voice(acc,channel,0);
            sprintf(msgtemp,"%s has been removed from VOP list.",username);
            sprintf(msgtemp2,"%s has removed you from VOP list of channel \"%s\"",conn_get_loggeduser(c),channel);
            changed = 1;
        }
        else
        {
            sprintf(msgtemp,"You must be at least Channel Admin to remove %s from the VOP list",username);
        }
        done = 1;
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    changed = 0;

    if ((dst_c) && channel_conn_has_tmpVOICE(conn_get_channel(c),dst_c)==1)
    {
        conn_set_tmpVOICE_channel(dst_c,NULL);
        sprintf(msgtemp,"Voice has been taken from %s in this channel",username);
        sprintf(msgtemp2,"%s has taken your Voice in channel \"%s\"",conn_get_loggeduser(c),channel);
        changed = 1;
        done = 1;
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);

    if (!done)
    {
        sprintf(msgtemp,"%s has no Voice in this channel, so it can't be taken away",username);
        message_send_text(c, message_type_info, c, msgtemp);
    }

    command_set_flags(dst_c);
    return 0;
}

static int _handle_op_command(t_connection * c, char const * text)
{
    char const *	username;
    char const *	channel;
    t_account *		acc;
    int			OP_lvl;
    t_connection * 	dst_c;
    int			changed = 0;

    if (!(conn_get_channel(c)) || !(channel = channel_get_name(conn_get_channel(c)))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    acc = conn_get_account(c);
    OP_lvl = 0;

    if (account_is_operator_or_admin(acc,channel)> 1)
        OP_lvl = 1;
    else if (channel_conn_is_tmpOP(conn_get_channel(c),c))
        OP_lvl = 2;

    if (OP_lvl==0)
    {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Operator or tempOP to use this command.");
        return -1;
    }

    text = skip_command(text);

    if (!(username = &text[0])) {
        message_send_text(c, message_type_info, c, "You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }

    dst_c = account_get_conn(acc);

    if (OP_lvl==1) // user is full op so he may fully op others
    {
		char const * tmp;
		tmp = account_get_strattr(acc,"BNET\\auth\\operator");
        if (tmp && str_get_bool(tmp)!=0)
//        if (account_is_operator_or_admin(acc,channel) >= 1)
            sprintf(msgtemp,"%s is already a Channel Operator",username);
        else if ((!(dst_c)) || (conn_get_channel(c) != conn_get_channel(dst_c)))
            sprintf(msgtemp,"%s must be on the same channel",username);
        else {
            account_set_auth_operator(acc,channel,1);
            sprintf(msgtemp,"%s has been promoted to a Channel Operator",username);
            sprintf(msgtemp2,"%s has promoted you to a Channel Operator in channel \"%s\"",conn_get_loggeduser(c),channel);
            changed = 1;
        }
    }
    else { // user is only tempOP so he may only tempOP others
        if ((!(dst_c)) || (conn_get_channel(c) != conn_get_channel(dst_c)))
            sprintf(msgtemp,"%s must be on the same channel to tempOP him",username);
        else
        {
            if (account_is_operator_or_admin(acc,channel))
                sprintf(msgtemp,"%s allready is operator or admin, no need to tempOP him",username);
            else
            {
                conn_set_tmpOP_channel(dst_c,channel);
                sprintf(msgtemp,"%s has been promoted to a tempOP",username);
                sprintf(msgtemp2,"%s has promoted you to a tempOP in this channel",conn_get_loggeduser(c));
                changed = 1;
            }
        }
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    command_set_flags(dst_c);
    return 0;
}

static int _handle_tmpop_command(t_connection * c, char const * text)
{
    char const *	username;
    char const *	channel;
    t_account *		acc;
    t_connection *	dst_c;
    int			changed = 0;

    if (!(conn_get_channel(c)) || !(channel = channel_get_name(conn_get_channel(c)))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    if (!(1<account_is_operator_or_admin(conn_get_account(c),channel_get_name(conn_get_channel(c))) || channel_conn_is_tmpOP(conn_get_channel(c),c))) {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Operator or tmpOP to use this command.");
        return -1;
    }

    text = skip_command(text);

    if (!(username = &text[0])) {
        message_send_text(c, message_type_info, c, "You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }

    dst_c = account_get_conn(acc);

    if (channel_conn_is_tmpOP(conn_get_channel(c),dst_c))
        sprintf(msgtemp,"%s has already tmpOP in this channel",username);
    else
    {
        if ((!(dst_c)) || (conn_get_channel(c) != conn_get_channel(dst_c)))
            sprintf(msgtemp,"%s must be on the same channel to tempOP him",username);
        else
        {
            if (account_is_operator_or_admin(acc,channel))
                sprintf(msgtemp,"%s allready is operator or admin, no need to tempOP him",username);
            else
            {
                conn_set_tmpOP_channel(dst_c,channel);
                sprintf(msgtemp,"%s has been promoted to tmpOP in this channel",username);
                sprintf(msgtemp2,"%s has promoted you to a tempOP in this channel",conn_get_loggeduser(c));
                changed = 1;
            }
        }
    }

    if (changed && dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
    message_send_text(c, message_type_info, c, msgtemp);
    command_set_flags(dst_c);
    return 0;
}

static int _handle_deop_command(t_connection * c, char const * text)
{
    char const *	username;
    char const *	channel;
    t_account *		acc;
    int			OP_lvl;
    t_connection *	dst_c;
    int			done = 0;

    if (!(conn_get_channel(c)) || !(channel = channel_get_name(conn_get_channel(c)))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    acc = conn_get_account(c);
    OP_lvl = 0;

    if (account_is_operator_or_admin(acc,channel)>=2)
        OP_lvl = 1;
    else if (channel_conn_is_tmpOP(conn_get_channel(c),account_get_conn(acc)))
        OP_lvl = 2;

    if (OP_lvl==0)
    {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Operator or tempOP to use this command.");
        return -1;
    }

    text = skip_command(text);

    if (!(username = &text[0])) {
        message_send_text(c, message_type_info, c, "You need to supply a username.");
        return -1;
    }

    if(!(acc = accountlist_find_account(username))) {
        sprintf(msgtemp, "There's no account with username %.64s.", username);
        message_send_text(c, message_type_info, c, msgtemp);
        return -1;
    }

    dst_c = account_get_conn(acc);

    if (OP_lvl==1) // user is real OP and allowed to deOP
    {
        if (account_get_auth_admin(acc,channel) == 1 || account_get_auth_operator(acc,channel) == 1) {
            if (account_get_auth_admin(acc,channel) == 1) {
                if (account_is_operator_or_admin(conn_get_account(c),channel)<=2)
                    message_send_text(c,message_type_info,c,"You must be at least a Channel Admin to demote another Channel Admin");
                else {
                    account_set_auth_admin(acc,channel,0);
                    sprintf(msgtemp, "%s has been demoted from a Channel Admin.", username);
                    message_send_text(c, message_type_info, c, msgtemp);
                    if (dst_c)
                    {
                        sprintf(msgtemp2,"%s has demoted you from a Channel Admin of channel \"%s\"",conn_get_loggeduser(c),channel);
                        message_send_text(dst_c, message_type_info, c, msgtemp2);
                    }
                }
            }
            if (account_get_auth_operator(acc,channel) == 1) {
                account_set_auth_operator(acc,channel,0);
                sprintf(msgtemp,"%s has been demoted from a Channel Operator",username);
                message_send_text(c, message_type_info, c, msgtemp);
                if (dst_c)
                {
                    sprintf(msgtemp2,"%s has demoted you from a Channel Operator of channel \"%s\"",conn_get_loggeduser(c),channel);
                    message_send_text(dst_c, message_type_info, c, msgtemp2);
                }
            }
            done = 1;
        }
        if ((dst_c) && channel_conn_is_tmpOP(conn_get_channel(c),dst_c))
        {
            conn_set_tmpOP_channel(dst_c,NULL);
            sprintf(msgtemp,"%s has been demoted from a tempOP of this channel",username);
            message_send_text(c, message_type_info, c, msgtemp);
            if (dst_c)
            {
                sprintf(msgtemp2,"%s has demoted you from a tmpOP of channel \"%s\"",conn_get_loggeduser(c),channel);
                message_send_text(dst_c, message_type_info, c, msgtemp2);
            }
            done = 1;
        }
        if (!done) {
            sprintf(msgtemp,"%s is no Channel Admin or Channel Operator or tempOP, so you can't demote him.",username);
            message_send_text(c, message_type_info, c, msgtemp);
        }
    }
    else //user is just a tempOP and may only deOP other tempOPs
    {
        if (dst_c && channel_conn_is_tmpOP(conn_get_channel(c),dst_c))
        {
            conn_set_tmpOP_channel(account_get_conn(acc),NULL);
            sprintf(msgtemp,"%s has been demoted from a tempOP of this channel",username);
            message_send_text(c, message_type_info, c, msgtemp);
            sprintf(msgtemp2,"%s has demoted you from a tempOP of channel \"%s\"",conn_get_loggeduser(c),channel);
            if (dst_c) message_send_text(dst_c, message_type_info, c, msgtemp2);
        }
        else
        {
            sprintf(msgtemp,"%s is no tempOP in this channel, so you can't demote him",username);
            message_send_text(c, message_type_info, c, msgtemp);
        }
    }

    command_set_flags(connlist_find_connection_by_accountname(username));
    return 0;
}

static int _handle_friends_command(t_connection * c, char const * text)
{
    int i;
    t_account *my_acc = conn_get_account(c);

    text = skip_command(text);;

    if(text[0]=='\0' || strstart(text,"help")==0 || strstart(text, "h")==0) {
        message_send_text(c,message_type_info,c,"Friends List (Used in Arranged Teams and finding online friends.)");
        message_send_text(c,message_type_info,c,"Type: /f add <username> (adds a friend_ to your list)");
        message_send_text(c,message_type_info,c,"Type: /f del <username> (removes a friend_ from your list)");
        message_send_text(c,message_type_info,c,"Type: /f promote <username> (promote a friend_ in your list)");
        message_send_text(c,message_type_info,c,"Type: /f demote <username> (demote a friend_ in your list)");
        message_send_text(c,message_type_info,c,"Type: /f list (shows your full friends list)");
        message_send_text(c,message_type_info,c,"Type: /f msg (whispers a message to all your friends at once)");
        return 0;
    }

    if (strstart(text,"add")==0 || strstart(text,"a")==0) {
        char msgtemp[MAX_MESSAGE_LEN];
        t_packet 	* rpacket;
        t_connection 	* dest_c;
        t_account    	* friend_acc;
        t_server_friendslistreply_status status;
        t_game * game;
        t_channel * channel;
        char stat;
        t_list * flist;
        t_friend * fr;

        text = skip_command(text);

        if (text[0] == '\0') {
            message_send_text(c,message_type_info,c,"usage: /f add <username>");
            return 0;
        }

        if (!(friend_acc = accountlist_find_account(text))) {
            message_send_text(c,message_type_info,c,"That user does not exist.");
            return 0;
        }

        switch(account_add_friend(my_acc, friend_acc)) {
        case -1:
            message_send_text(c,message_type_error,c,"Server error.");
            return 0;
        case -2:
            message_send_text(c,message_type_info,c,"You can't add yourself to your friends list.");
            return 0;
        case -3:
            sprintf(msgtemp, "You can only have a maximum of %d friends.", prefs_get_max_friends());
            message_send_text(c,message_type_info,c,msgtemp);
            return 0;
        case -4:
            sprintf(msgtemp, "%s is already on your friends list!", text);
            message_send_text(c,message_type_info,c,msgtemp);
            return 0;
        }

        sprintf( msgtemp, "Added %s to your friends list.", text);
        message_send_text(c,message_type_info,c,msgtemp);
        dest_c = connlist_find_connection_by_account(friend_acc);
///        if(dest_c!=NULL) {
///            sprintf(msgtemp,"%s added you to his/her friends list.",conn_get_username(c));
///            message_send_text(dest_c,message_type_info,dest_c,msgtemp);
///        }

        if ((conn_get_class(c)!=conn_class_bnet) || (!(rpacket = packet_create(packet_class_bnet))))
            return 0;

        packet_set_size(rpacket,sizeof(t_server_friendadd_ack));
        packet_set_type(rpacket,SERVER_FRIENDADD_ACK);

        packet_append_string(rpacket, account_get_name(friend_acc));

        game = NULL;
        channel = NULL;

        if(!(dest_c))
        {
            bn_byte_set(&status.location,FRIENDSTATUS_OFFLINE);
            bn_byte_set(&status.status,0);
            bn_int_set(&status.clienttag,0);
        }
        else
        {
            bn_int_set(&status.clienttag, conn_get_clienttag(dest_c));
            stat = 0;
            flist = account_get_friends(my_acc);
            fr = friendlist_find_account(flist,friend_acc);
            if ((friend_get_mutual(fr)))    stat |= FRIEND_TYPE_MUTUAL;
            if ((conn_get_dndstr(dest_c,0)))  stat |= FRIEND_TYPE_DND;
            if ((conn_get_awaystr(dest_c))) stat |= FRIEND_TYPE_AWAY;
            bn_byte_set(&status.status,stat);
            if((game = conn_get_game(dest_c)))
            {
                if (game_get_flag(game) != game_flag_private)
                    bn_byte_set(&status.location,FRIENDSTATUS_PUBLIC_GAME);
                else
                    bn_byte_set(&status.location,FRIENDSTATUS_PRIVATE_GAME);
            }
            else if((channel = conn_get_channel(dest_c)))
            {
                bn_byte_set(&status.location,FRIENDSTATUS_CHAT);
            }
            else
            {
                bn_byte_set(&status.location,FRIENDSTATUS_ONLINE);
            }
        }

        packet_append_data(rpacket, &status, sizeof(status));

        if (game) packet_append_string(rpacket,game_get_name(game));
        else if (channel) packet_append_string(rpacket,channel_get_name(channel));
        else packet_append_string(rpacket,"");

        conn_push_outqueue(c,rpacket);
        packet_del_ref(rpacket);

        return 0;
    }

    if (strstart(text,"msg")==0 || strstart(text,"w")==0 || strstart(text,"whisper")==0 || strstart(text,"m")==0)
    {
        char const *msg;
        int cnt = 0;
        t_connection * dest_c;
        t_elem  * curr;
        t_friend * fr;
        t_list  * flist;

        msg = skip_command(text);
        /* if the message test is empty then ignore command */
        if (msg[0]=='\0') {
            message_send_text(c,message_type_info,c,"Did not message any friends. Type some text next time.");
            return 0;
        }

        flist=account_get_friends(my_acc);
        if(flist==NULL)
            return -1;

        LIST_TRAVERSE(flist,curr)
        {
            if (!(fr = (t_friend*)elem_get_data(curr))) {
                eventlog(eventlog_level_error,__FUNCTION__,"found NULL entry in list");
                continue;
            }
            if(friend_get_mutual(fr)) {
                dest_c = connlist_find_connection_by_account(friend_get_account(fr));
                if (!dest_c) continue;
				if(conn_get_dndstr(dest_c,1))
				{
					sprintf(msgtemp,"%s is refusing messages (%.128s)",
							account_get_name(friend_get_account(fr)),
							conn_get_dndstr(dest_c,1));
					message_send_text(c,message_type_info,c,msgtemp);
					continue;
				}
                message_send_text(dest_c,message_type_whisper,c,msg);
                cnt++;
            }
        }
        if(cnt)
            message_send_text(c,message_type_friendwhisperack,c,msg);
        else
            message_send_text(c,message_type_info,c,"All your friends are offline.");

        return 0;
    }

    if (strstart(text,"r")==0 || strstart(text,"remove")==0
            || strstart(text,"del")==0 || strstart(text,"delete")==0) {

        int num;
        char msgtemp[MAX_MESSAGE_LEN];
        t_packet * rpacket;

        text = skip_command(text);

        if (text[0]=='\0') {
            message_send_text(c,message_type_info,c,"usage: /f remove <username>");
            return 0;
        }

        switch((num = account_remove_friend2(my_acc, text))) {
		case -1:
			return -1;
        case -2:
            sprintf(msgtemp, "%s was not found on your friends list.", text);
            message_send_text(c,message_type_info,c,msgtemp);
            return 0;
        default:
            sprintf(msgtemp, "Removed %s from your friends list.", text);
            message_send_text(c,message_type_info,c,msgtemp);

            if ((conn_get_class(c)!=conn_class_bnet) || (!(rpacket = packet_create(packet_class_bnet))))
                return 0;

            packet_set_size(rpacket,sizeof(t_server_frienddel_ack));
            packet_set_type(rpacket,SERVER_FRIENDDEL_ACK);

            bn_byte_set(&rpacket->u.server_frienddel_ack.friendnum, num);

            conn_push_outqueue(c,rpacket);
            packet_del_ref(rpacket);

            return 0;
        }
    }

    if (strstart(text,"p")==0 || strstart(text,"promote")==0) {
        int num;
        int n;
        char msgtemp[MAX_MESSAGE_LEN];
        char const * dest_name;
        t_packet * rpacket;
        t_list * flist;
        t_friend * fr;
        t_account * dest_acc;
        unsigned int dest_uid;

        text = skip_command(text);

        if (text[0]=='\0') {
            message_send_text(c,message_type_info,c,"usage: /f promote <username>");
            return 0;
        }

        num = account_get_friendcount(my_acc);
        flist = account_get_friends(my_acc);
        for(n = 1; n<num; n++)
            if( (dest_uid = account_get_friend(my_acc, n)) &&
                    (fr = friendlist_find_uid(flist, dest_uid)) &&
                    (dest_acc = friend_get_account(fr)) &&
                    (dest_name = account_get_name(dest_acc)) &&
                    (strcasecmp(dest_name, text) == 0) )
            {
                account_set_friend(my_acc, n, account_get_friend(my_acc, n-1));
                account_set_friend(my_acc, n-1, dest_uid);
                sprintf(msgtemp, "Premoted %s in your friends list.", dest_name);
                message_send_text(c,message_type_info,c,msgtemp);

                if ((conn_get_class(c)!=conn_class_bnet) || (!(rpacket = packet_create(packet_class_bnet))))
                    return 0;

                packet_set_size(rpacket,sizeof(t_server_friendmove_ack));
                packet_set_type(rpacket,SERVER_FRIENDMOVE_ACK);
                bn_byte_set(&rpacket->u.server_friendmove_ack.pos1, n-1);
                bn_byte_set(&rpacket->u.server_friendmove_ack.pos2, n);

                conn_push_outqueue(c,rpacket);
                packet_del_ref(rpacket);
                return 0;
            }
        return 0;
    }

    if (strstart(text,"d")==0 || strstart(text,"demote")==0) {
        int num;
        int n;
        char msgtemp[MAX_MESSAGE_LEN];
        char const * dest_name;
        t_packet * rpacket;
        t_list * flist;
        t_friend * fr;
        t_account * dest_acc;
        unsigned int dest_uid;

        text = skip_command(text);

        if (text[0]=='\0') {
            message_send_text(c,message_type_info,c,"usage: /f demote <username>");
            return 0;
        }

        num = account_get_friendcount(my_acc);
        flist = account_get_friends(my_acc);
        for(n = 0; n<num-1; n++)
            if( (dest_uid = account_get_friend(my_acc, n)) &&
                    (fr = friendlist_find_uid(flist, dest_uid)) &&
                    (dest_acc = friend_get_account(fr)) &&
                    (dest_name = account_get_name(dest_acc)) &&
                    (strcasecmp(dest_name, text) == 0) )
            {
                account_set_friend(my_acc, n, account_get_friend(my_acc, n+1));
                account_set_friend(my_acc, n+1, dest_uid);
                sprintf(msgtemp, "Premoted %s in your friends list.", dest_name);
                message_send_text(c,message_type_info,c,msgtemp);

                if ((conn_get_class(c)!=conn_class_bnet) || (!(rpacket = packet_create(packet_class_bnet))))
                    return 0;

                packet_set_size(rpacket,sizeof(t_server_friendmove_ack));
                packet_set_type(rpacket,SERVER_FRIENDMOVE_ACK);
                bn_byte_set(&rpacket->u.server_friendmove_ack.pos1, n);
                bn_byte_set(&rpacket->u.server_friendmove_ack.pos2, n+1);

                conn_push_outqueue(c,rpacket);
                packet_del_ref(rpacket);
                return 0;
            }
        return 0;
    }

    if (strstart(text,"list")==0 || strstart(text,"l")==0) {
        char const * friend_;
        char status[128];
        char software[64];
        char msgtemp[MAX_MESSAGE_LEN];
        t_connection * dest_c;
        t_account * friend_acc;
        t_game const * game;
        t_channel const * channel;
        t_friend * fr;
        t_list  * flist;
        int num;
        unsigned int uid;

        message_send_text(c,message_type_info,c,"Your PvPGN - Friends List");
        message_send_text(c,message_type_info,c,"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
        num = account_get_friendcount(my_acc);

        flist=account_get_friends(my_acc);
        if(flist!=NULL) {
            for (i=0;i<num;i++)
            {
                if ((!(uid = account_get_friend(my_acc,i))) || (!(fr = friendlist_find_uid(flist,uid))))
                {
                    eventlog(eventlog_level_error,__FUNCTION__,"friend_ uid in list");
                    continue;
                }
                software[0]='\0';
                friend_acc=friend_get_account(fr);
                if (!(dest_c = connlist_find_connection_by_account(friend_acc)))
                    sprintf(status, ", offline");
                else {
                    sprintf(software," using %s", clienttag_get_title(conn_get_clienttag(dest_c)));

                    if(friend_get_mutual(fr)) {
                        if ((game = conn_get_game(dest_c)))
                            sprintf(status, ", in game \"%.64s\"", game_get_name(game));
                        else if ((channel = conn_get_channel(dest_c))) {
                            if(strcasecmp(channel_get_name(channel),"Arranged Teams")==0)
                                sprintf(status, ", in game AT Preparation");
                            else
                                sprintf(status, ", in channel \"%.64s\",", channel_get_name(channel));
                        }
                        else
                            sprintf(status, ", is in AT Preparation");
                    } else {
                        if ((game = conn_get_game(dest_c)))
                            sprintf(status, ", is in a game");
                        else if ((channel = conn_get_channel(dest_c)))
                            sprintf(status, ", is in a chat channel");
                        else
                            sprintf(status, ", is in AT Preparation");
                    }
                }

                friend_=account_get_name(friend_acc);
                if (software[0]) sprintf(msgtemp, "%d: %s%.16s%.128s, %.64s", i+1, friend_get_mutual(fr)?"*":" ", friend_, status,software);
                else sprintf(msgtemp, "%d: %.16s%.128s", i+1, friend_, status);
                message_send_text(c,message_type_info,c,msgtemp);
            }
        }
        message_send_text(c,message_type_info,c,"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
        message_send_text(c,message_type_info,c,"End of Friends List");

        return 0;
    }

    return 0;
}

static int _handle_me_command(t_connection * c, char const * text)
{
    t_channel const * channel;

    if (!(channel = conn_get_channel(c)))
    {
        message_send_text(c,message_type_error,c,"You are not in a channel.");
        return 0;
    }

    text = skip_command(text);

    if ((text[0]!='\0') && (!conn_quota_exceeded(c,text)))
        channel_message_send(channel,message_type_emote,c,text);
    return 0;
}

static int _handle_whisper_command(t_connection * c, char const *text)
{
    char         dest[USER_NAME_MAX+REALM_NAME_LEN]; /* both include NUL, so no need to add one for middle @ or * */
    unsigned int i,j;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if ((dest[0]=='\0') || (text[i]=='\0'))
    {
        message_send_text(c,message_type_info,c,"usage: /whisper <username> <text to whisper>");
        return 0;
    }

    do_whisper(c,dest,&text[i]);

    return 0;
}

static int _handle_status_command(t_connection * c, char const *text)
{
    char ctag[5];
    unsigned int i,j;
    t_clienttag clienttag;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get clienttag */
        if (j<sizeof(ctag)-1) ctag[j++] = text[i];
    ctag[j] = '\0';

    if (ctag[0]=='\0') {
        sprintf(msgtemp,"There are currently %d users online, in %d games and %d channels.",
                connlist_login_get_length(),
                gamelist_get_length(),
                channellist_get_length());
        message_send_text(c,message_type_info,c,msgtemp);
        tag_uint_to_str(ctag,conn_get_clienttag(c));
    }

    for (i=0; i<strlen(ctag); i++)
        if (isascii((int)ctag[i]) && islower((int)ctag[i]))
            ctag[i] = toupper((int)ctag[i]);

    if (strcmp(ctag,"ALL") == 0)
        clienttag = 0;
    else
        clienttag = tag_case_str_to_uint(ctag);

    switch (clienttag)
    {
    case 0:
    case CLIENTTAG_WAR3XP_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_WAR3XP_UINT),
                game_get_count_by_clienttag(CLIENTTAG_WAR3XP_UINT),
                clienttag_get_title(CLIENTTAG_WAR3XP_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    case CLIENTTAG_WARCRAFT3_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_WARCRAFT3_UINT),
                game_get_count_by_clienttag(CLIENTTAG_WARCRAFT3_UINT),
                clienttag_get_title(CLIENTTAG_WARCRAFT3_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    case CLIENTTAG_DIABLO2XP_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_DIABLO2XP_UINT),
                game_get_count_by_clienttag(CLIENTTAG_DIABLO2XP_UINT),
                clienttag_get_title(CLIENTTAG_DIABLO2XP_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    case CLIENTTAG_DIABLO2DV_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_DIABLO2DV_UINT),
                game_get_count_by_clienttag(CLIENTTAG_DIABLO2DV_UINT),
                clienttag_get_title(CLIENTTAG_DIABLO2DV_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    case CLIENTTAG_BROODWARS_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_BROODWARS_UINT),
                game_get_count_by_clienttag(CLIENTTAG_BROODWARS_UINT),
                clienttag_get_title(CLIENTTAG_BROODWARS_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    case CLIENTTAG_STARCRAFT_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_STARCRAFT_UINT),
                game_get_count_by_clienttag(CLIENTTAG_STARCRAFT_UINT),
                clienttag_get_title(CLIENTTAG_STARCRAFT_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    case CLIENTTAG_WARCIIBNE_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_WARCIIBNE_UINT),
                game_get_count_by_clienttag(CLIENTTAG_WARCIIBNE_UINT),
                clienttag_get_title(CLIENTTAG_WARCIIBNE_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    case CLIENTTAG_DIABLORTL_UINT:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(CLIENTTAG_DIABLORTL_UINT),
                game_get_count_by_clienttag(CLIENTTAG_DIABLORTL_UINT),
                clienttag_get_title(CLIENTTAG_DIABLORTL_UINT));
        message_send_text(c,message_type_info,c,msgtemp);
        if (clienttag) break;
    default:
        sprintf(msgtemp,"There are currently %u user(s) in %u games of %s",
                conn_get_user_count_by_clienttag(conn_get_clienttag(c)),
                game_get_count_by_clienttag(conn_get_clienttag(c)),
                clienttag_get_title(conn_get_clienttag(c)));
        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_who_command(t_connection * c, char const *text)
{
    t_connection const * conn;
    t_channel const *    channel;
    unsigned int         i;
    char const *         tname;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /who <channel>");
        return 0;
    }

    if (!(channel = channellist_find_channel_by_name(&text[i],conn_get_country(c),realm_get_name(conn_get_realm(c)))))
    {
        message_send_text(c,message_type_error,c,"That channel does not exist.");
        message_send_text(c,message_type_error,c,"(If you are trying to search for a user, use the /whois command.)");
        return 0;
    }
    if (channel_check_banning(channel,c)==1)
    {
        message_send_text(c,message_type_error,c,"You are banned from that channel.");
        return 0;
    }

    sprintf(msgtemp,"Users in channel %.64s:",&text[i]);
    i = strlen(msgtemp);
    for (conn=channel_get_first(channel); conn; conn=channel_get_next())
    {
        if (i+strlen((tname = conn_get_username(conn)))+2>sizeof(msgtemp)) /* " ", name, '\0' */
        {
            message_send_text(c,message_type_info,c,msgtemp);
            i = 0;
        }
        sprintf(&msgtemp[i]," %s",tname);
        i += strlen(&msgtemp[i]);
    }
    if (i>0)
        message_send_text(c,message_type_info,c,msgtemp);

    return 0;
}

static int _handle_whois_command(t_connection * c, char const * text)
{
    unsigned int i;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /whois <username>");
        return 0;
    }

    do_whois(c,&text[i]);

    return 0;
}

static int _handle_whoami_command(t_connection * c, char const *text)
{
    char const * tname;

    if (!(tname = conn_get_username(c)))
    {
        message_send_text(c,message_type_error,c,"Unable to obtain your account name.");
        return 0;
    }

    do_whois(c,tname);

    return 0;
}

static int _handle_announce_command(t_connection * c, char const *text)
{
    unsigned int i;
    t_message *  message;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /announce <announcement>");
        return 0;
    }

    sprintf(msgtemp,"(Admin) : %.128s",&text[i]);
    if (!(message = message_create(message_type_broadcast,c,NULL,msgtemp)))
        message_send_text(c,message_type_info,c,"Could not broadcast message.");
    else
    {
        if (message_send_all(message)<0)
            message_send_text(c,message_type_info,c,"Could not broadcast message.");
        message_destroy(message);
    }
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);

    return 0;
}

static int _handle_beep_command(t_connection * c, char const *text)
{
    message_send_text(c,message_type_info,c,"Audible notification on."); /* FIXME: actually do something */
    return 0; /* FIXME: these only affect CHAT clients... I think they prevent ^G from being sent */
}

static int _handle_nobeep_command(t_connection * c, char const *text)
{
    message_send_text(c,message_type_info,c,"Audible notification off."); /* FIXME: actually do something */
    return 0;
}

static int _handle_version_command(t_connection * c, char const *text)
{
    message_send_text(c,message_type_info,c,PVPGN_SOFTWARE" "PVPGN_VERSION);
    return 0;
}

static int _handle_copyright_command(t_connection * c, char const *text)
{
    static char const * const info[] =
        {
            " Copyright (C) 2002  See source for details",
            " ",
            " PvPGN is free software; you can redistribute it and/or",
            " modify it under the terms of the GNU General Public License",
            " as published by the Free Software Foundation; either version 2",
            " of the License, or (at your option) any later version.",
            " ",
            " This program is distributed in the hope that it will be useful,",
            " but WITHOUT ANY WARRANTY; without even the implied warranty of",
            " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
            " GNU General Public License for more details.",
            " ",
            " You should have received a copy of the GNU General Public License",
            " along with this program; if not, write to the Free Software",
            " Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.",
            NULL
        };
    unsigned int i;

    for (i=0; info[i]; i++)
        message_send_text(c,message_type_info,c,info[i]);

    return 0;
}

static int _handle_uptime_command(t_connection * c, char const *text)
{

    sprintf(msgtemp,"Uptime: %s",seconds_to_timestr(server_get_uptime()));
    message_send_text(c,message_type_info,c,msgtemp);

    return 0;
}

static int _handle_stats_command(t_connection * c, char const *text)
{
    char         dest[USER_NAME_MAX];
    unsigned int i,j;
    t_account *  account;
    char const * clienttag=NULL;
    t_clienttag  clienttag_uint;
    char         clienttag_str[5];

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (!dest[0]) {
        account = conn_get_account(c);
    } else if (!(account = accountlist_find_account(dest))) {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }

    if (text[i]!='\0')
        clienttag = &text[i];
    else if (!(clienttag = tag_uint_to_str(clienttag_str,conn_get_clienttag(c)))) {
        message_send_text(c,message_type_error,c,"Unable to determine client game.");
        return 0;
    }

    if (strlen(clienttag)!=4) {
        sprintf(msgtemp,"You must supply a user name and a valid program ID. (Program ID \"%.32s\" is invalid.)",clienttag);
        message_send_text(c,message_type_error,c,msgtemp);
        message_send_text(c,message_type_error,c,"Example: /stats joe STAR");
        return 0;
    }

    clienttag_uint = tag_case_str_to_uint(clienttag);

    switch (clienttag_uint)
    {
    case CLIENTTAG_BNCHATBOT_UINT:
        message_send_text(c,message_type_error,c,"This game does not support win/loss records.");
        message_send_text(c,message_type_error,c,"You must supply a user name and a valid program ID.");
        message_send_text(c,message_type_error,c,"Example: /stats joe STAR");
        return 0;
    case CLIENTTAG_DIABLORTL_UINT:
    case CLIENTTAG_DIABLOSHR_UINT:
        sprintf(msgtemp,"%.64s's record:",account_get_name(account));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"level: %u",account_get_normal_level(account,clienttag_uint));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"classs: %.16s",bnclass_get_str(account_get_normal_class(account,clienttag_uint)));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"stats: %u str  %u mag  %u dex  %u vit  %u gld",
                account_get_normal_strength(account,clienttag_uint),
                account_get_normal_magic(account,clienttag_uint),
                account_get_normal_dexterity(account,clienttag_uint),
                account_get_normal_vitality(account,clienttag_uint),
                account_get_normal_gold(account,clienttag_uint));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"Diablo kills: %u",account_get_normal_diablo_kills(account,clienttag_uint));
        message_send_text(c,message_type_info,c,msgtemp);
        return 0;
    case CLIENTTAG_WARCIIBNE_UINT:
        sprintf(msgtemp,"%.64s's record:",account_get_name(account));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"Normal games: %u-%u-%u",
                account_get_normal_wins(account,clienttag_uint),
                account_get_normal_losses(account,clienttag_uint),
                account_get_normal_disconnects(account,clienttag_uint));
        message_send_text(c,message_type_info,c,msgtemp);
        if (account_get_ladder_rating(account,clienttag_uint,ladder_id_normal)>0)
            sprintf(msgtemp,"Ladder games: %u-%u-%u (rating %d)",
                    account_get_ladder_wins(account,clienttag_uint,ladder_id_normal),
                    account_get_ladder_losses(account,clienttag_uint,ladder_id_normal),
                    account_get_ladder_disconnects(account,clienttag_uint,ladder_id_normal),
                    account_get_ladder_rating(account,clienttag_uint,ladder_id_normal));
        else
            strcpy(msgtemp,"Ladder games: 0-0-0");
        message_send_text(c,message_type_info,c,msgtemp);
        if (account_get_ladder_rating(account,clienttag_uint,ladder_id_ironman)>0)
            sprintf(msgtemp,"IronMan games: %u-%u-%u (rating %d)",
                    account_get_ladder_wins(account,clienttag_uint,ladder_id_ironman),
                    account_get_ladder_losses(account,clienttag_uint,ladder_id_ironman),
                    account_get_ladder_disconnects(account,clienttag_uint,ladder_id_ironman),
                    account_get_ladder_rating(account,clienttag_uint,ladder_id_ironman));
        else
            strcpy(msgtemp,"IronMan games: 0-0-0");
        message_send_text(c,message_type_info,c,msgtemp);
        return 0;
    case CLIENTTAG_WARCRAFT3_UINT:
    case CLIENTTAG_WAR3XP_UINT:
        sprintf(msgtemp,"%.64s's Ladder Record's:",account_get_name(account));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"Users Solo Level: %u, Experience: %u",
                account_get_ladder_level(account,clienttag_uint,ladder_id_solo),
                account_get_ladder_xp(account,clienttag_uint,ladder_id_solo));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"SOLO Ladder Record: %u-%u-0",
                account_get_ladder_wins(account,clienttag_uint,ladder_id_solo),
                account_get_ladder_losses(account,clienttag_uint,ladder_id_solo));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"SOLO Rank: %u",
                account_get_ladder_rank(account,clienttag_uint,ladder_id_solo));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"Users Team Level: %u, Experience: %u",
                account_get_ladder_level(account,clienttag_uint,ladder_id_team),
                account_get_ladder_xp(account,clienttag_uint,ladder_id_team));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"TEAM Ladder Record: %u-%u-0",
                account_get_ladder_wins(account,clienttag_uint,ladder_id_team),
                account_get_ladder_losses(account,clienttag_uint,ladder_id_team));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"TEAM Rank: %u",
                account_get_ladder_rank(account,clienttag_uint,ladder_id_team));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"Users FFA Level: %u, Experience: %u",
                account_get_ladder_level(account,clienttag_uint,ladder_id_ffa),
                account_get_ladder_xp(account,clienttag_uint,ladder_id_ffa));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"FFA Ladder Record: %u-%u-0",
                account_get_ladder_wins(account,clienttag_uint,ladder_id_ffa),
                account_get_ladder_losses(account,clienttag_uint,ladder_id_ffa));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"FFA Rank: %u",
                account_get_ladder_rank(account,clienttag_uint,ladder_id_ffa));
        message_send_text(c,message_type_info,c,msgtemp);
        if (account_get_teams(account)) {
            t_elem * curr;
            t_list * list;
            t_team * team;
            int teamcount = 0;

            list = account_get_teams(account);

            LIST_TRAVERSE(list,curr)
            {
                if (!(team = (t_team*)elem_get_data(curr)))
                {
                    eventlog(eventlog_level_error, __FUNCTION__, "found NULL entry in list");
                    continue;
                }

                if (team_get_clienttag(team) != clienttag_uint)
                    continue;

                teamcount++;
                sprintf(msgtemp,"Users AT Team No. %u",teamcount);
                message_send_text(c,message_type_info,c,msgtemp);
                sprintf(msgtemp,"Users AT TEAM Level: %u, Experience: %u",
                        team_get_level(team),team_get_xp(team));
                message_send_text(c,message_type_info,c,msgtemp);
                sprintf(msgtemp,"AT TEAM Ladder Record: %u-%u-0",
                        team_get_wins(team),team_get_losses(team));
                message_send_text(c,message_type_info,c,msgtemp);
                sprintf(msgtemp,"AT TEAM Rank: %u",
                        team_get_rank(team));
                message_send_text(c,message_type_info,c,msgtemp);
            }
        }
        return 0;
    default:
        sprintf(msgtemp,"%.64s's record:",account_get_name(account));
        message_send_text(c,message_type_info,c,msgtemp);
        sprintf(msgtemp,"Normal games: %u-%u-%u",
                account_get_normal_wins(account,clienttag_uint),
                account_get_normal_losses(account,clienttag_uint),
                account_get_normal_disconnects(account,clienttag_uint));
        message_send_text(c,message_type_info,c,msgtemp);
        if (account_get_ladder_rating(account,clienttag_uint,ladder_id_normal)>0)
            sprintf(msgtemp,"Ladder games: %u-%u-%u (rating %d)",
                    account_get_ladder_wins(account,clienttag_uint,ladder_id_normal),
                    account_get_ladder_losses(account,clienttag_uint,ladder_id_normal),
                    account_get_ladder_disconnects(account,clienttag_uint,ladder_id_normal),
                    account_get_ladder_rating(account,clienttag_uint,ladder_id_normal));
        else
            strcpy(msgtemp,"Ladder games: 0-0-0");
        message_send_text(c,message_type_info,c,msgtemp);
        return 0;
    }
}

static int _handle_time_command(t_connection * c, char const *text)
{
    t_bnettime  btsystem;
    t_bnettime  btlocal;
    time_t      now;
    struct tm * tmnow;

    btsystem = bnettime();

    /* Battle.net time: Wed Jun 23 15:15:29 */
    btlocal = bnettime_add_tzbias(btsystem,local_tzbias());
    now = bnettime_to_time(btlocal);
    if (!(tmnow = gmtime(&now)))
        strcpy(msgtemp,"PvPGN Server Time: ?");
    else
        strftime(msgtemp,sizeof(msgtemp),"PvPGN Server Time: %a %b %d %H:%M:%S",tmnow);
    message_send_text(c,message_type_info,c,msgtemp);
    if (conn_get_class(c)==conn_class_bnet)
    {
        btlocal = bnettime_add_tzbias(btsystem,conn_get_tzbias(c));
        now = bnettime_to_time(btlocal);
        if (!(tmnow = gmtime(&now)))
            strcpy(msgtemp,"Your local time: ?");
        else
            strftime(msgtemp,sizeof(msgtemp),"Your local time: %a %b %d %H:%M:%S",tmnow);
        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_channel_command(t_connection * c, char const *text)
{
    t_channel * channel;

    text = skip_command(text);

    if (text[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage /channel <channel>");
        return 0;
    }

    if(strcasecmp(text,"Arranged Teams")==0)
    {
        //       if(account_get_auth_admin(conn_get_account(c))>0)
        //	 {
        //	   message_send_text(c,message_type_error,c,"Please do not talk in channel Arranged Teams");
        //	   message_send_text(c,message_type_error,c,"This channel is dedicated for the preparation of");
        //	   message_send_text(c,message_type_error,c,"Arranged Team Games.");
        //	 }
        //       else
        //	 {
        message_send_text(c,message_type_error,c,"Channel Arranged Teams is a RESTRICTED Channel!");
        return 0;
        //	 }
    }

    if ((channel = conn_get_channel(c)) && (strcasecmp(channel_get_name(channel),text)==0))
        return 0; // we don't have to do anything, we are allready in this channel

    if (conn_set_channel(c,text)<0)
        conn_set_channel(c,CHANNEL_NAME_BANNED); /* should not fail */
    if ((conn_get_clienttag(c) == CLIENTTAG_WARCRAFT3_UINT) || (conn_get_clienttag(c) == CLIENTTAG_WAR3XP_UINT))
        conn_update_w3_playerinfo(c);
    command_set_flags(c);

    return 0;
}

static int _handle_rejoin_command(t_connection * c, char const *text)
{

    if (channel_rejoin(c)!=0)
        message_send_text(c,message_type_error,c,"You are not in a channel.");
    if ((conn_get_clienttag(c) == CLIENTTAG_WARCRAFT3_UINT) || (conn_get_clienttag(c) ==  CLIENTTAG_WAR3XP_UINT))
        conn_update_w3_playerinfo(c);
    command_set_flags(c);

    return 0;
}

static int _handle_away_command(t_connection * c, char const *text)
{

    text = skip_command(text);

    if (text[0]=='\0') /* toggle away mode */
    {
        if (!conn_get_awaystr(c))
        {
            message_send_text(c,message_type_info,c,"You are now marked as being away.");
            conn_set_awaystr(c,"Currently not available");
        }
        else
        {
            message_send_text(c,message_type_info,c,"You are no longer marked as away.");
            conn_set_awaystr(c,NULL);
        }
    }
    else
    {
        message_send_text(c,message_type_info,c,"You are now marked as being away.");
        conn_set_awaystr(c,text);
    }

    return 0;
}

static int _handle_dnd_command(t_connection * c, char const *text)
{

    text = skip_command(text);

    if (text[0]=='\0') /* toggle dnd mode */
    {
        if (!conn_get_dndstr(c,0))
        {
            message_send_text(c,message_type_info,c,"Do Not Diturb mode engaged.");
            conn_set_dndstr(c,"Not available");
        }
        else
        {
            message_send_text(c,message_type_info,c,"Do Not Disturb mode cancelled.");
            conn_set_dndstr(c,NULL);
        }
    }
    else
    {
        message_send_text(c,message_type_info,c,"Do Not Disturb mode engaged.");
        conn_set_dndstr(c,text);
    }

    return 0;
}

static int _handle_squelch_command(t_connection * c, char const *text)
{
    t_account *  account;

    text = skip_command(text);

    /* D2 puts * before username */
    if (text[0]=='*')
        text++;

    if (text[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /squelch <username>");
        return 0;
    }

    if (!(account = accountlist_find_account(text)))
    {
        message_send_text(c,message_type_error,c,"No such user.");
        return 0;
    }

    if (conn_get_account(c)==account)
    {
        message_send_text(c,message_type_error,c,"You can't squelch yourself.");
        return 0;
    }

    if (conn_add_ignore(c,account)<0)
        message_send_text(c,message_type_error,c,"Could not squelch user.");
    else
    {
        sprintf(msgtemp,"%-.20s has been squelched.",account_get_name(account));
        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_unsquelch_command(t_connection * c, char const *text)
{
    t_account * account;
    t_connection * dest_c;

    text = skip_command(text);

    /* D2 puts * before username */
    if (text[0]=='*')
        text++;

    if (text[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /unsquelch <username>");
        return 0;
    }

    if (!(account = accountlist_find_account(text)))
    {
        message_send_text(c,message_type_info,c,"No such user.");
        return 0;
    }

    if (conn_del_ignore(c,account)<0)
        message_send_text(c,message_type_info,c,"User was not being ignored.");
    else
    {
        t_message * message;

        message_send_text(c,message_type_info,c,"No longer ignoring.");

        if ((dest_c = account_get_conn(account)))
        {
            if (!(message = message_create(message_type_userflags,dest_c,NULL,NULL))) /* handles NULL text */
                return 0;
            message_send(message,c);
            message_destroy(message);
        }
    }

    return 0;
}

static int _handle_kick_command(t_connection * c, char const *text)
{
    char              dest[USER_NAME_MAX];
    unsigned int      i,j;
    t_channel const * channel;
    t_connection *    kuc;
    t_account *	    acc;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /kick <username>");
        return 0;
    }

    if (!(channel = conn_get_channel(c)))
    {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return 0;
    }

    acc = conn_get_account(c);
    if (!account_is_operator_or_admin(acc,channel_get_name(channel))  && /* default to false */
            !channel_conn_is_tmpOP(channel,account_get_conn(acc)))
    {
        message_send_text(c,message_type_error,c,"You have to be at least a Channel Operator or tempOP to use this command.");
        return 0;
    }
    if (!(kuc = connlist_find_connection_by_accountname(dest)))
    {
        message_send_text(c,message_type_error,c,"That user is not logged in.");
        return 0;
    }
    if (conn_get_channel(kuc)!=channel)
    {
        message_send_text(c,message_type_error,c,"That user is not in this channel.");
        return 0;
    }
    if (account_is_operator_or_admin(conn_get_account(kuc),channel_get_name(channel)))
    {
        message_send_text(c,message_type_error,c,"You cannot kick administrators.");
        return 0;
    }


    {
        char const * tname1;
        char const * tname2;

        tname1 = conn_get_loggeduser(kuc);
        tname2 = conn_get_loggeduser(c);
        if (!tname1 || !tname2) {
            eventlog(eventlog_level_error, __FUNCTION__, "got NULL username");
            return -1;
        }

        if (text[i]!='\0')
            sprintf(msgtemp,"%-.20s has been kicked by %-.20s (%s).",tname1,tname2,&text[i]);
        else
            sprintf(msgtemp,"%-.20s has been kicked by %-.20s.",tname1,tname2);
        channel_message_send(channel,message_type_info,c,msgtemp);
    }
    conn_set_channel(kuc,CHANNEL_NAME_KICKED); /* should not fail */

    return 0;
}

static int _handle_ban_command(t_connection * c, char const *text)
{
    char           dest[USER_NAME_MAX];
    unsigned int   i,j;
    t_channel *    channel;
    t_connection * buc;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage. /ban <username>");
        return 0;
    }

    if (!(channel = conn_get_channel(c)))
    {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return 0;
    }
    if (!account_is_operator_or_admin(conn_get_account(c),channel_get_name(channel))) /* default to false */
    {
        message_send_text(c,message_type_error,c,"You have to be at least a Channel Operator to use this command.");
        return 0;
    }
    {
        t_account * account;

        if (!(account = accountlist_find_account(dest)))
            message_send_text(c,message_type_info,c,"That account doesn't currently exist, banning anyway.");
        else if (account_is_operator_or_admin(account,channel_get_name(channel)))
        {
            message_send_text(c,message_type_error,c,"You cannot ban administrators.");
            return 0;
        }

    }

    if (channel_ban_user(channel,dest)<0)
    {
        sprintf(msgtemp,"Unable to ban %-.20s.",dest);
        message_send_text(c,message_type_error,c,msgtemp);
    }
    else
    {
        char const * tname;

        tname = conn_get_loggeduser(c);
        if (text[i]!='\0')
            sprintf(msgtemp,"%-.20s has been banned by %-.20s (%s).",dest,tname?tname:"unknown",&text[i]);
        else
            sprintf(msgtemp,"%-.20s has been banned by %-.20s.",dest,tname?tname:"unknown");
        channel_message_send(channel,message_type_info,c,msgtemp);
    }
    if ((buc = connlist_find_connection_by_accountname(dest)) &&
            conn_get_channel(buc)==channel)
        conn_set_channel(buc,CHANNEL_NAME_BANNED);

    return 0;
}

static int _handle_unban_command(t_connection * c, char const *text)
{
    t_channel *  channel;
    unsigned int i;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /unban <username>");
        return 0;
    }

    if (!(channel = conn_get_channel(c)))
    {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return 0;
    }
    if (!account_is_operator_or_admin(conn_get_account(c),channel_get_name(channel))) /* default to false */
    {
        message_send_text(c,message_type_error,c,"You are not a channel operator.");
        return 0;
    }

    if (channel_unban_user(channel,&text[i])<0)
        message_send_text(c,message_type_error,c,"That user is not banned.");
    else
    {
        sprintf(msgtemp,"%s is no longer banned from this channel.",&text[i]);
        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_reply_command(t_connection * c, char const *text)
{
    unsigned int i;
    char const * dest;

    if (!(dest = conn_get_lastsender(c)))
    {
        message_send_text(c,message_type_error,c,"No one messaged you, use /m instead");
        return 0;
    }

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /reply <replytext>");
        return 0;
    }
    do_whisper(c,dest,&text[i]);
    return 0;
}

static int _handle_realmann_command(t_connection * c, char const *text)
{
    unsigned int i;
    t_realm * realm;
    t_realm * trealm;
    t_connection * tc;
    t_elem const * curr;
    t_message    * message;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (!(realm=conn_get_realm(c))) {
        message_send_text(c,message_type_info,c,"You must join a realm first");
        return 0;
    }

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /realmann <announcement text>");
        return 0;
    }

    sprintf(msgtemp,"Announcement from %.32s@%.32s: %.128s",conn_get_username(c),realm_get_name(realm),&text[i]);
    if (!(message = message_create(message_type_broadcast,c,NULL,msgtemp)))
    {
        message_send_text(c,message_type_info,c,"Could not broadcast message.");
    }
    else
    {
		BEGIN(it,connlist())
        {
            tc = *it;
            if (!tc)
                continue;
            if ((trealm = conn_get_realm(tc)) && (trealm==realm))
            {
                message_send(message,tc);
            }
        }
    }
    return 0;
}

static int _handle_watch_command(t_connection * c, char const *text)
{
    unsigned int i;
    t_account *  account;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /watch <username>");
        return 0;
    }
    if (!(account = accountlist_find_account(&text[i])))
    {
        message_send_text(c,message_type_info,c,"That user does not exist.");
        return 0;
    }

    if (conn_add_watch(c,account,0)<0) /* FIXME: adds all events for now */
        message_send_text(c,message_type_error,c,"Add to watch list failed.");
    else
    {
        sprintf(msgtemp,"User %.64s added to your watch list.",&text[i]);
        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_unwatch_command(t_connection * c, char const *text)
{
    unsigned int i;
    t_account *  account;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /unwatch <username>");
        return 0;
    }
    if (!(account = accountlist_find_account(&text[i])))
    {
        message_send_text(c,message_type_info,c,"That user does not exist.");
        return 0;
    }

    if (conn_del_watch(c,account,0)<0) /* FIXME: deletes all events for now */
        message_send_text(c,message_type_error,c,"Removal from watch list failed.");
    else
    {
        sprintf(msgtemp,"User %.64s removed from your watch list.",&text[i]);
        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_watchall_command(t_connection * c, char const *text)
{
    t_clienttag clienttag=0;
    char clienttag_str[5];

    text = skip_command(text);

    if(text[0] != '\0') {
        if (strlen(text) != 4) {
            message_send_text(c,message_type_error,c,"You must supply a rank and a valid program ID.");
            message_send_text(c,message_type_error,c,"Example: /watchall STAR");
            return 0;
        }
        clienttag = tag_case_str_to_uint(text);
    }

    if (conn_add_watch(c,NULL,clienttag)<0) /* FIXME: adds all events for now */
        message_send_text(c,message_type_error,c,"Add to watch list failed.");
    else
        if(clienttag) {
            char msgtemp[MAX_MESSAGE_LEN];
            sprintf(msgtemp, "All %s users added to your watch list.", tag_uint_to_str(clienttag_str,clienttag));
            message_send_text(c,message_type_info,c,msgtemp);
        }
        else
            message_send_text(c,message_type_info,c,"All users added to your watch list.");

    return 0;
}

static int _handle_unwatchall_command(t_connection * c, char const *text)
{
    t_clienttag clienttag=0;
    char clienttag_str[5];

    text = skip_command(text);

    if(text[0] != '\0') {
        if (strlen(text) != 4) {
            message_send_text(c,message_type_error,c,"You must supply a rank and a valid program ID.");
            message_send_text(c,message_type_error,c,"Example: /unwatchall STAR");
        }
        clienttag = tag_case_str_to_uint(text);
    }

    if (conn_del_watch(c,NULL,clienttag)<0) /* FIXME: deletes all events for now */
        message_send_text(c,message_type_error,c,"Removal from watch list failed.");
    else
        if(clienttag) {
            char msgtemp[MAX_MESSAGE_LEN];
            sprintf(msgtemp, "All %s users removed from your watch list.", tag_uint_to_str(clienttag_str,clienttag));
            message_send_text(c,message_type_info,c,msgtemp);
        }
        else
            message_send_text(c,message_type_info,c,"All users removed from your watch list.");

    return 0;
}

static int _handle_lusers_command(t_connection * c, char const *text)
{
    t_channel *    channel;
    t_elem const * curr;
    char const *   banned;
    unsigned int   i;

    if (!(channel = conn_get_channel(c)))
    {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return 0;
    }

    strcpy(msgtemp,"Banned users:");
    i = strlen(msgtemp);
    LIST_TRAVERSE_CONST(channel_get_banlist(channel),curr)
    {
        banned = (const char *)elem_get_data(curr);
        if (i+strlen(banned)+2>sizeof(msgtemp)) /* " ", name, '\0' */
        {
            message_send_text(c,message_type_info,c,msgtemp);
            i = 0;
        }
        sprintf(&msgtemp[i]," %s",banned);
        i += strlen(&msgtemp[i]);
    }
    if (i>0)
        message_send_text(c,message_type_info,c,msgtemp);

    return 0;
}

static int _news_cb(time_t date, t_lstr *lstr, void *data)
{
    char	strdate[64];
    struct tm 	*tm;
    char	save, *p, *q;
    t_connection *c = (t_connection*)data;

    tm = localtime(&date);
    if (tm) strftime(strdate, 64,"%B %d, %Y", tm);
    else strcpy(strdate, "(invalid date)");
    message_send_text(c,message_type_info,c,strdate);

    for (p = lstr_get_str(lstr); *p;) {
        for(q = p; *q && *q != '\r' && *q != '\n';q++);
        save = *q;
        *q = '\0';
        message_send_text(c,message_type_info,c,p);
        *q = save;
        p = q;
        for(;*p == '\n' || *p == '\r';p++);
    }

    return 0;
}

static int _handle_news_command(t_connection * c, char const *text)
{
    news_traverse(_news_cb,c);
    return 0;
}

struct glist_cb_struct {
    t_game_difficulty diff;
    t_clienttag tag;
    t_connection *c;
};

static int _glist_cb(t_game *game, void *data)
{
    struct glist_cb_struct *cbdata = (struct glist_cb_struct*)data;

    if ((!cbdata->tag || !prefs_get_hide_pass_games() || game_get_flag(game) != game_flag_private) &&
            (!cbdata->tag || game_get_clienttag(game)==cbdata->tag) &&
            (cbdata->diff==game_difficulty_none || game_get_difficulty(game)==cbdata->diff))
    {
        sprintf(msgtemp," %-16.16s %1.1s %-8.8s %-21.21s %5u ",
                game_get_name(game),
                game_get_flag(game) != game_flag_private ? "n":"y",
                game_status_get_str(game_get_status(game)),
                game_type_get_str(game_get_type(game)),
                game_get_ref(game));

        if (!cbdata->tag)
        {

            strcat(msgtemp,clienttag_uint_to_str(game_get_clienttag(game)));
            strcat(msgtemp," ");
        }

        if ((!prefs_get_hide_addr()) || (account_get_command_groups(conn_get_account(cbdata->c)) & command_get_group("/admin-addr"))) /* default to false */
            strcat(msgtemp, addr_num_to_addr_str(game_get_addr(game),game_get_port(game)));

        message_send_text(cbdata->c,message_type_info,cbdata->c,msgtemp);
    }

    return 0;
}

static int _handle_games_command(t_connection * c, char const *text)
{
    unsigned int   i;
    unsigned int   j;
    char           clienttag_str[5];
    char           dest[5];
    struct glist_cb_struct cbdata;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    cbdata.c = c;

    if(strcmp(&text[i],"norm")==0)
        cbdata.diff = game_difficulty_normal;
    else if(strcmp(&text[i],"night")==0)
        cbdata.diff = game_difficulty_nightmare;
    else if(strcmp(&text[i],"hell")==0)
        cbdata.diff = game_difficulty_hell;
    else
        cbdata.diff = game_difficulty_none;

    if (dest[0]=='\0')
    {
        cbdata.tag = conn_get_clienttag(c);
        message_send_text(c,message_type_info,c,"Currently accessable games:");
    }
    else if (strcasecmp(&dest[0],"all")==0)
    {
        cbdata.tag = 0;
        message_send_text(c,message_type_info,c,"All current games:");
    }
    else
    {
        cbdata.tag = tag_case_str_to_uint(&dest[0]);

        if (!tag_check_client(cbdata.tag))
        {
            message_send_text(c,message_type_error,c,"No valid clienttag specified.");
            return -1;
        }

        if(cbdata.diff==game_difficulty_none)
            sprintf(msgtemp,"Current games of type %s",tag_uint_to_str(clienttag_str,cbdata.tag));
        else
            sprintf(msgtemp,"Current games of type %s %s",tag_uint_to_str(clienttag_str,cbdata.tag),&text[i]);
        message_send_text(c,message_type_info,c,msgtemp);
    }

    sprintf(msgtemp," ------name------ p -status- --------type--------- count ");
    if (!cbdata.tag)
        strcat(msgtemp,"ctag ");
    if ((!prefs_get_hide_addr()) || (account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-addr"))) /* default to false */
        strcat(msgtemp,"--------addr--------");
    message_send_text(c,message_type_info,c,msgtemp);
    gamelist_traverse(_glist_cb,&cbdata);

    return 0;
}

static int _handle_channels_command(t_connection * c, char const *text)
{
    unsigned int      i;
    t_elem const *    curr;
    t_channel const * channel;
    char const *      tag;
    t_connection const * conn;
    t_account * acc;
    char const * name;
    int first;


    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        tag = clienttag_uint_to_str(conn_get_clienttag(c));
        message_send_text(c,message_type_info,c,"Currently accessable channels:");
    }
    else if (strcmp(&text[i],"all")==0)
    {
        tag = NULL;
        message_send_text(c,message_type_info,c,"All current channels:");
    }
    else
    {
        tag = &text[i];
        sprintf(msgtemp,"Current channels of type %s",tag);
        message_send_text(c,message_type_info,c,msgtemp);
    }

    sprintf(msgtemp," -----------name----------- users ----admin/operator----");
    message_send_text(c,message_type_info,c,msgtemp);
///    LIST_TRAVERSE_CONST(channellist(),curr)
///    {
///        channel = (const t_channel*)elem_get_data(curr);
	BEGIN(_ch,channellist())
	{
		channel=*_ch;
        if ((!(channel_get_flags(channel) & channel_flags_clan)) && (!tag || !prefs_get_hide_temp_channels() || channel_get_permanent(channel)) &&
                (!tag || !channel_get_clienttag(channel) ||
                 strcasecmp(channel_get_clienttag(channel),tag)==0) &&
                ((channel_get_max(channel)!=0) || //only show restricted channels to OPs and Admins
                 ((channel_get_max(channel)==0 && account_is_operator_or_admin(conn_get_account(c),NULL)))) &&
                (!(channel_get_flags(channel) & channel_flags_thevoid)) // don't list TheVoid
           )
        {

            sprintf(msgtemp," %-26.26s %5u - ",
                    channel_get_name(channel),
                    channel_get_length(channel));
            if(strncasecmp(channel_get_name(channel),"ch-",3))
            {
                continue;
            }
            if(strncasecmp(channel_get_name(channel),"op ",3))
            {
                continue;
            }

            first = 1;

            for (conn = channel_get_first(channel);conn;conn=channel_get_next())
            {
                acc = conn_get_account(conn);
                if (account_is_operator_or_admin(acc,channel_get_name(channel)) ||
                        channel_conn_is_tmpOP(channel,account_get_conn(acc)))
                {
                    name = conn_get_loggeduser(conn);
                    if (strlen(msgtemp) + strlen(name) +6 >= MAX_MESSAGE_LEN) break;
                    if (!first) strcat(msgtemp," ,");
                    strcat(msgtemp,name);
                    if (account_get_auth_admin(acc,NULL)==1) strcat(msgtemp,"(A)");
                    else if (account_get_auth_operator(acc,NULL)==1) strcat(msgtemp,"(O)");
                    else if (account_get_auth_admin(acc,channel_get_name(channel))==1) strcat(msgtemp,"(a)");
                    else if (account_get_auth_operator(acc,channel_get_name(channel))==1) strcat(msgtemp,"(o)");
                    first = 0;
                }
            }

            message_send_text(c,message_type_info,c,msgtemp);
        }
    }

    return 0;
}

static int _handle_addacct_command(t_connection * c, char const *text)
{
    unsigned int i,j;
    t_account  * temp;
    t_hash       passhash;
    char         username[USER_NAME_MAX];
    char         pass[256];

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++);
    for (; text[i]==' '; i++);

    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get username */
        if (j<sizeof(username)-1) username[j++] = text[i];
    username[j] = '\0';

    for (; text[i]==' '; i++); /* skip spaces */
    for (j=0; text[i]!='\0'; i++) /* get pass (spaces are allowed) */
        if (j<sizeof(pass)-1) pass[j++] = text[i];
    pass[j] = '\0';

    if (username[0]=='\0' || pass[0]=='\0') {
        message_send_text(c,message_type_info,c,"usage: /addacct <username> <password>");
        return 0;
    }

    if (account_check_name(username)<0) {
        message_send_text(c,message_type_error,c,"Account name contains some invalid symbol!");
        return 0;
    }

    /* FIXME: truncate or err on too long password */
    for (i=0; i<strlen(pass); i++)
        if (isupper((int)pass[i])) pass[i] = tolower((int)pass[i]);

    bnet_hash(&passhash,strlen(pass),pass);

    sprintf(msgtemp,"Trying to add account \"%s\" with password \"%s\"",username,pass);
    message_send_text(c,message_type_info,c,msgtemp);

    sprintf(msgtemp,"Hash is: %s",hash_get_str(passhash));
    message_send_text(c,message_type_info,c,msgtemp);

    temp = accountlist_create_account(username,hash_get_str(passhash));
    if (!temp) {
        message_send_text(c,message_type_error,c,"Failed to create account!");
        eventlog(eventlog_level_debug,__FUNCTION__,"[%d] account \"%s\" not created (failed)",conn_get_socket(c),username);
        return 0;
    }

    sprintf(msgtemp,"Account "UID_FORMAT" created.",account_get_uid(temp));
    message_send_text(c,message_type_info,c,msgtemp);
    eventlog(eventlog_level_debug,__FUNCTION__,"[%d] account \"%s\" created",conn_get_socket(c),username);

    return 0;
}

static int _handle_chpass_command(t_connection * c, char const *text)
{
    unsigned int i,j;
    t_account  * account;
    t_account  * temp;
    t_hash       passhash;
    char         arg1[256];
    char         arg2[256];
    char const * username;
    char *       pass;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++);
    for (; text[i]==' '; i++);

    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get username/pass */
        if (j<sizeof(arg1)-1) arg1[j++] = text[i];
    arg1[j] = '\0';

    for (; text[i]==' '; i++); /* skip spaces */
    for (j=0; text[i]!='\0'; i++) /* get pass (spaces are allowed) */
        if (j<sizeof(arg2)-1) arg2[j++] = text[i];
    arg2[j] = '\0';

    if (arg2[0]=='\0')
    {
        username = conn_get_username(c);
        pass     = arg1;
    }
    else
    {
        username = arg1;
        pass     = arg2;
    }

    if (pass[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /chpass [username] <password>");
        return 0;
    }

    temp = accountlist_find_account(username);

    account = conn_get_account(c);

    if ((temp==account && account_get_auth_changepass(account)==0) || /* default to true */
            (temp!=account && !(account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-chpass")))) /* default to false */
    {
        eventlog(eventlog_level_info,__FUNCTION__,"[%d] password change for \"%s\" refused (no change access)",conn_get_socket(c),username);
        message_send_text(c,message_type_error,c,"Only admins may change passwords for other accounts.");
        return 0;
    }

    if (!temp)
    {
        message_send_text(c,message_type_error,c,"Account does not exist.");
        return 0;
    }

    if (strlen(pass) > USER_PASS_MAX)
    {
        sprintf(msgtemp,"Maximum password length allowed is %d",USER_PASS_MAX);
        message_send_text(c,message_type_error,c,msgtemp);
        return 0;
    }

    for (i=0; i<strlen(pass); i++)
        if (isupper((int)pass[i])) pass[i] = tolower((int)pass[i]);

    bnet_hash(&passhash,strlen(pass),pass);

    sprintf(msgtemp,"Trying to change password for account \"%s\" to \"%s\"",username,pass);
    message_send_text(c,message_type_info,c,msgtemp);

    if (account_set_pass(temp,hash_get_str(passhash))<0)
    {
        message_send_text(c,message_type_error,c,"Unable to set password.");
        return 0;
    }

    if (account_get_auth_admin(account,NULL) == 1 ||
            account_get_auth_operator(account,NULL) == 1) {
        sprintf(msgtemp,
                "Password for account "UID_FORMAT" updated.",account_get_uid(temp));
        message_send_text(c,message_type_info,c,msgtemp);

        sprintf(msgtemp,"Hash is: %s",hash_get_str(passhash));
        message_send_text(c,message_type_info,c,msgtemp);
    } else {
        sprintf(msgtemp,
                "Password for account %s updated.",username);
        message_send_text(c,message_type_info,c,msgtemp);
    }
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);

    return 0;
}

static int _handle_connections_command(t_connection *c, char const *text)
{
    t_elem const * curr;
    t_connection * conn;
    char           name[19];
    unsigned int   i; /* for loop */
    char const *   channel_name;
    char const *   game_name;
    char           clienttag_str[5];

    if (!prefs_get_enable_conn_all() && !(account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-con"))) /* default to false */
    {
        message_send_text(c,message_type_error,c,"This command is only enabled for admins.");
        return 0;
    }

    message_send_text(c,message_type_info,c,"Current connections:");
    /* addon */
    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        sprintf(msgtemp," -class -tag -----name------ -lat(ms)- ----channel---- --game--");
        message_send_text(c,message_type_info,c,msgtemp);
    }
    else
        if (strcmp(&text[i],"all")==0) /* print extended info */
        {
            if (prefs_get_hide_addr() && !(account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-addr")))
                sprintf(msgtemp," -#- -class ----state--- -tag -----name------ -session-- -flag- -lat(ms)- ----channel---- --game--");
            else
                sprintf(msgtemp," -#- -class ----state--- -tag -----name------ -session-- -flag- -lat(ms)- ----channel---- --game-- ---------addr--------");
            message_send_text(c,message_type_info,c,msgtemp);
        }
        else
        {
            message_send_text(c,message_type_error,c,"Unknown option.");
            return 0;
        }

    BEGIN(it,connlist())
    {
        conn = *it;
        if (conn_get_account(conn))
            sprintf(name,"\"%.16s\"",conn_get_username(conn));
        else
            strcpy(name,"(none)");

        if (conn_get_channel(conn)!=NULL)
            channel_name = channel_get_name(conn_get_channel(conn));
        else channel_name = "none";
        if (conn_get_game(conn)!=NULL)
            game_name = game_get_name(conn_get_game(conn));
        else game_name = "none";

        if (text[i]=='\0')
            sprintf(msgtemp," %-6.6s %4.4s %-15.15s %9u %-16.16s %-8.8s",
                    conn_class_get_str(conn_get_class(conn)),
                    tag_uint_to_str(clienttag_str,conn_get_fake_clienttag(conn)),
                    name,
                    conn_get_latency(conn),
                    channel_name,
                    game_name);
        else
            if (prefs_get_hide_addr() && !(account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-addr"))) /* default to false */
                sprintf(msgtemp," %3d %-6.6s %-12.12s %4.4s %-15.15s 0x%08x 0x%04x %9u %-16.16s %-8.8s",
                        conn_get_socket(conn),
                        conn_class_get_str(conn_get_class(conn)),
                        conn_state_get_str(conn_get_state(conn)),
                        tag_uint_to_str(clienttag_str,conn_get_fake_clienttag(conn)),
                        name,
                        conn_get_sessionkey(conn),
                        conn_get_flags(conn),
                        conn_get_latency(conn),
                        channel_name,
                        game_name);
            else
                sprintf(msgtemp," %3u %-6.6s %-12.12s %4.4s %-15.15s 0x%08x 0x%04x %9u %-16.16s %-8.8s %s",
                        conn_get_socket(conn),
                        conn_class_get_str(conn_get_class(conn)),
                        conn_state_get_str(conn_get_state(conn)),
                        tag_uint_to_str(clienttag_str,conn_get_fake_clienttag(conn)),
                        name,
                        conn_get_sessionkey(conn),
                        conn_get_flags(conn),
                        conn_get_latency(conn),
                        channel_name,
                        game_name,
                        addr_num_to_addr_str(conn_get_addr(conn),conn_get_port(conn)));

        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_finger_command(t_connection * c, char const *text)
{
    char           dest[USER_NAME_MAX];
    unsigned int   i,j;
    t_account *    account;
    t_connection * conn;
    char const *   ip;
    char *         tok;
    t_clanmember * clanmemb;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /finger <account>");
        return 0;
    }

    if (!(account = accountlist_find_account(dest)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }
    sprintf(msgtemp,"Login: %-16.16s "UID_FORMAT" Sex: %.14s",
            account_get_name(account),
            account_get_uid(account),
            account_get_sex(account));
    message_send_text(c,message_type_info,c,msgtemp);

    if ((clanmemb = account_get_clanmember(account)))
    {
        t_clan *	 clan;
        char	 status;

        if ((clan = clanmember_get_clan(clanmemb)))
        {
            sprintf(msgtemp,"Clan : %-64.64s",clan_get_name(clan));
            if ((status = clanmember_get_status(clanmemb)))
            {
                switch (status)
                {
                case CLAN_CHIEFTAIN:
                    strcat(msgtemp,"  Rank: Chieftain");
                    break;
                case CLAN_SHAMAN:
                    strcat(msgtemp,"  Rank: Shaman");
                    break;
                case CLAN_GRUNT:
                    strcat(msgtemp,"  Rank: Grunt");
                    break;
                case CLAN_PEON:
                    strcat(msgtemp,"  Rank: Peon");
                    break;
                default:;
                }
            }
            message_send_text(c,message_type_info,c,msgtemp);

        }
    }

    sprintf(msgtemp,"Location: %-23.23s Age: %.14s",
            account_get_loc(account),
            account_get_age(account));
    message_send_text(c,message_type_info,c,msgtemp);

    if((conn = connlist_find_connection_by_accountname(dest)))
    {
        sprintf(msgtemp,"Client: %s    Ver: %s   Country: %s",
                clienttag_get_title(conn_get_clienttag(conn)),
                conn_get_clientver(conn),
                conn_get_country(conn));
        message_send_text(c,message_type_info,c,msgtemp);
    }

    if (!(ip=account_get_ll_ip(account)) ||
            !(account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-addr"))) /* default to false */
        ip = "unknown";

    {
        time_t      then;
        struct tm * tmthen;

        then = account_get_ll_time(account);
        tmthen = localtime(&then); /* FIXME: determine user's timezone */
        if (!(conn))
            if (tmthen)
                strftime(msgtemp,sizeof(msgtemp),"Last login %a %b %d %H:%M %Y from ",tmthen);
            else
                strcpy(msgtemp,"Last login ? from ");
        else
            if (tmthen)
                strftime(msgtemp,sizeof(msgtemp),"On since %a %b %d %H:%M %Y from ",tmthen);
            else
                strcpy(msgtemp,"On since ? from ");
    }
	if(string(ip)!="unknown" && !(account_get_command_groups(conn_get_account(c)) & (~(unsigned int)1)))
	{
		stringstream ss,ss2;
		string strIP(ip);
		BEGIN(ch,strIP)
			if(*ch=='.')
				*ch=' ';

		ss<<ip;

		int numIP[4]={0,0,0,0};
		REP(i,3)
			ss>>numIP[i];

		ss.str("");

		ss2<<numIP[0]<<"."<<"XXX"<<"."<<numIP[2]<<"."<<numIP[3];
	    strncat(msgtemp,ss2.str().c_str(),32);
	}
	else
	    strncat(msgtemp,ip,32);
    message_send_text(c,message_type_info,c,msgtemp);

    if (conn)
    {
        sprintf(msgtemp,"Idle %s",seconds_to_timestr(conn_get_idletime(conn)));
        message_send_text(c,message_type_info,c,msgtemp);
    }

    strncpy(msgtemp,account_get_desc(account),sizeof(msgtemp));
    msgtemp[sizeof(msgtemp)-1] = '\0';
    for (tok=strtok(msgtemp,"\r\n"); tok; tok=strtok(NULL,"\r\n"))
        message_send_text(c,message_type_info,c,tok);
    message_send_text(c,message_type_info,c,"");

    return 0;
}

/*
 * rewrote command /operator to add and remove operator status [Omega]
 *
 * Fixme: rewrite /operators to show Currently logged on Server and/or Channel operators ...??
 */
/*
static int _handle_operator_command(t_connection * c, char const *text)
{
  t_connection const * opr;
  t_channel const *    channel;
  
  if (!(channel = conn_get_channel(c)))
    {
      message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
      return 0;
    }
  
  if (!(opr = channel_get_operator(channel)))
    strcpy(msgtemp,"There is no operator.");
  else
      sprintf(msgtemp,"%.64s is the operator.",conn_get_username(opr));
  message_send_text(c,message_type_info,c,msgtemp);
  return 0;
}
*/

/* FIXME: do we want to show just Server Admin or Channel Admin Also? [Omega] */
static int _handle_admins_command(t_connection * c, char const *text)
{
    unsigned int    i;
    t_elem const *  curr;
    t_connection *  tc;
    char const *    nick;

    strcpy(msgtemp,"Currently logged on Administrators:");
    i = strlen(msgtemp);
    BEGIN(it,connlist())
    {
        tc = *it;
        if (!tc)
            continue;
        if (!conn_get_account(tc))
            continue;
        if (account_get_auth_admin(conn_get_account(tc),NULL)==1)
        {
            if ((nick = conn_get_username(tc)))
            {
                if (i+strlen(nick)+2>sizeof(msgtemp)) /* " ", name, '\0' */
                {
                    message_send_text(c,message_type_info,c,msgtemp);
                    i = 0;
                }
                sprintf(&msgtemp[i]," %s", nick);
                i += strlen(&msgtemp[i]);
            }
        }
    }
    if (i>0)
        message_send_text(c,message_type_info,c,msgtemp);

    return 0;
}

static int _handle_quit_command(t_connection * c, char const *text)
{
    if (conn_get_game(c))
        eventlog(eventlog_level_warn, __FUNCTION__,"[%d] user '%d' tried to disconnect while in game, cheat attempt ?", conn_get_socket(c), conn_get_loggeduser(c));
    else {
        message_send_text(c,message_type_info,c,"Connection closed.");
        conn_set_state(c,conn_state_destroy);
    }

    return 0;
}

static int _handle_kill_command(t_connection * c, char const *text)
{
    unsigned int	i,j;
    t_connection *	user;
    char		usrnick[USER_NAME_MAX]; /* max length of nick + \0 */  /* FIXME: Is it somewhere defined? */

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get nick */
        if (j<sizeof(usrnick)-1) usrnick[j++] = text[i];
    usrnick[j]='\0';
    for (; text[i]==' '; i++);

    if (usrnick[0]=='\0' || (usrnick[0]=='#' && (usrnick[1] < '0' || usrnick[1] > '9')))
    {
        message_send_text(c,message_type_info,c,"usage: /kill {<username>|#<socket>} [<min>]");
        return 0;
    }

    if (usrnick[0] == '#') {
        if (!(user = connlist_find_connection_by_socket(atoi(usrnick + 1)))) {
            message_send_text(c,message_type_error,c,"That connection doesnt exist.");
            return 0;
        }
    } else {
        if (!(user = connlist_find_connection_by_accountname(usrnick))) {
            message_send_text(c,message_type_error,c,"That user is not logged in?");
            return 0;
        }
    }

    if (text[i]!='\0' && ipbanlist_add(c,addr_num_to_ip_str(conn_get_addr(user)),ipbanlist_str_to_time_t(c,&text[i]))==0)
    {
        ipbanlist_save(prefs_get_ipbanfile());
        message_send_text(user,message_type_info,user,"Connection closed by admin and banned your ip.");
    }
    else
        message_send_text(user,message_type_info,user,"Connection closed by admin.");
    conn_set_state(user,conn_state_destroy);

    message_send_text(c,message_type_info,c,"Operation successful.");

    return 0;
}

static int _handle_killsession_command(t_connection * c, char const *text)
{
    unsigned int	i,j;
    t_connection *	user;
    char		session[16];

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get nick */
        if (j<sizeof(session)-1) session[j++] = text[i];
    session[j]='\0';
    for (; text[i]==' '; i++);

    if (session[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /killsession <session> [min]");
        return 0;
    }
    if (!isxdigit((int)session[0]))
    {
        message_send_text(c,message_type_error,c,"That is not a valid session.");
        return 0;
    }
    if (!(user = connlist_find_connection_by_sessionkey((unsigned int)strtoul(session,NULL,16))))
    {
        message_send_text(c,message_type_error,c,"That session does not exist.");
        return 0;
    }
    if (text[i]!='\0' && ipbanlist_add(c,addr_num_to_ip_str(conn_get_addr(user)),ipbanlist_str_to_time_t(c,&text[i]))==0)
    {
        ipbanlist_save(prefs_get_ipbanfile());
        message_send_text(user,message_type_info,user,"Connection closed by admin and banned your ip's.");
    }
    else
        message_send_text(user,message_type_info,user,"Connection closed by admin.");
    conn_set_state(user,conn_state_destroy);
    return 0;
}

static int _handle_gameinfo_command(t_connection * c, char const *text)
{
    unsigned int   i;
    t_game const * game;
    char clienttag_str[5];

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        if (!(game = conn_get_game(c)))
        {
            message_send_text(c,message_type_error,c,"You are not in a game.");
            return 0;
        }
    }
    else
        if (!(game = gamelist_find_game(&text[i],conn_get_clienttag(c),game_type_all)))
        {
            message_send_text(c,message_type_error,c,"That game does not exist.");
            return 0;
        }

    sprintf(msgtemp,"Name: %-20.20s    ID: "GAMEID_FORMAT" (%s)",game_get_name(game),game_get_id(game),game_get_flag(game) != game_flag_private ? "public":"private");
    message_send_text(c,message_type_info,c,msgtemp);

    {
        t_account *  owner;
        char const * tname;
        char const * namestr;

        if (!(owner = conn_get_account(game_get_owner(game))))
        {
            tname = NULL;
            namestr = "none";
        }
        else
            if (!(tname = conn_get_loggeduser(game_get_owner(game))))
                namestr = "unknown";
            else
                namestr = tname;

        sprintf(msgtemp,"Owner: %-20.20s",namestr);

    }
    message_send_text(c,message_type_info,c,msgtemp);

    if (!prefs_get_hide_addr() || (account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-addr"))) /* default to false */
    {
        unsigned int   addr;
        unsigned short port;
        unsigned int   taddr;
        unsigned short tport;

        taddr=addr = game_get_addr(game);
        tport=port = game_get_port(game);
        trans_net(conn_get_addr(c),&taddr,&tport);

        if (taddr==addr && tport==port)
            sprintf(msgtemp,"Address: %s",
                    addr_num_to_addr_str(addr,port));
        else
            sprintf(msgtemp,"Address: %s (trans %s)",
                    addr_num_to_addr_str(addr,port),
                    addr_num_to_addr_str(taddr,tport));
        message_send_text(c,message_type_info,c,msgtemp);
    }

    sprintf(msgtemp,"Client: %4s (version %s, startver %u)",tag_uint_to_str(clienttag_str,game_get_clienttag(game)),vernum_to_verstr(game_get_version(game)),game_get_startver(game));
    message_send_text(c,message_type_info,c,msgtemp);

    {
        time_t      gametime;
        struct tm * gmgametime;

        gametime = game_get_create_time(game);
        if (!(gmgametime = localtime(&gametime)))
            strcpy(msgtemp,"Created: ?");
        else
            strftime(msgtemp,sizeof(msgtemp),"Created: "GAME_TIME_FORMAT,gmgametime);
        message_send_text(c,message_type_info,c,msgtemp);

        gametime = game_get_start_time(game);
        if (gametime!=(time_t)0)
        {
            if (!(gmgametime = localtime(&gametime)))
                strcpy(msgtemp,"Started: ?");
            else
                strftime(msgtemp,sizeof(msgtemp),"Started: "GAME_TIME_FORMAT,gmgametime);
        }
        else
            strcpy(msgtemp,"Started: ");
        message_send_text(c,message_type_info,c,msgtemp);
    }

    sprintf(msgtemp,"Status: %s",game_status_get_str(game_get_status(game)));
    message_send_text(c,message_type_info,c,msgtemp);

    sprintf(msgtemp,"Type: %-20.20s",game_type_get_str(game_get_type(game)));
    message_send_text(c,message_type_info,c,msgtemp);

    sprintf(msgtemp,"Speed: %s",game_speed_get_str(game_get_speed(game)));
    message_send_text(c,message_type_info,c,msgtemp);

    sprintf(msgtemp,"Difficulty: %s",game_difficulty_get_str(game_get_difficulty(game)));
    message_send_text(c,message_type_info,c,msgtemp);

    sprintf(msgtemp,"Option: %s",game_option_get_str(game_get_option(game)));
    message_send_text(c,message_type_info,c,msgtemp);

    {
        char const * mapname;

        if (!(mapname = game_get_mapname(game)))
            mapname = "unknown";
        sprintf(msgtemp,"Map: %-20.20s",mapname);
        message_send_text(c,message_type_info,c,msgtemp);
    }

    sprintf(msgtemp,"Map Size: %ux%u",game_get_mapsize_x(game),game_get_mapsize_y(game));
    message_send_text(c,message_type_info,c,msgtemp);
    sprintf(msgtemp,"Map Tileset: %s",game_tileset_get_str(game_get_tileset(game)));
    message_send_text(c,message_type_info,c,msgtemp);
    sprintf(msgtemp,"Map Type: %s",game_maptype_get_str(game_get_maptype(game)));
    message_send_text(c,message_type_info,c,msgtemp);

    sprintf(msgtemp,"Players: %u current, %u total, %u max",game_get_ref(game),game_get_count(game),game_get_maxplayers(game));
    message_send_text(c,message_type_info,c,msgtemp);

    {
        char const * description;

        if (!(description = game_get_description(game)))
            description = "";
        sprintf(msgtemp,"Description: %-20.20s",description);
    }

    return 0;
}

static int _handle_ladderactivate_command(t_connection * c, char const *text)
{
    ladderlist_make_all_active();
    message_send_text(c,message_type_info,c,"Copied current scores to active scores on all ladders.");
    return 0;
}

static int _handle_rehash_command(t_connection * c, char const *text)
{
    server_restart_wraper();
    return 0;
}

/*
static int _handle_rank_all_accounts_command(t_connection * c, char const *text)
{
  // rank all accounts here
  accounts_rank_all();
  return 0;
}
*/

static int _handle_shutdown_command(t_connection * c, char const *text)
{
    char         dest[32];
    unsigned int i,j;
    unsigned int delay;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
        delay = prefs_get_shutdown_delay();
    else
        if (clockstr_to_seconds(dest,&delay)<0)
        {
            message_send_text(c,message_type_error,c,"Invalid delay.");
            return 0;
        }

    server_quit_delay(delay);

    if (delay)
        message_send_text(c,message_type_info,c,"You initialized the shutdown sequence.");
    else
        message_send_text(c,message_type_info,c,"You canceled the shutdown sequence.");

    return 0;
}

static int _handle_ladderinfo_command(t_connection * c, char const *text)
{
    char         dest[32];
    unsigned int rank;
    unsigned int i,j;
    t_account *  account;
    t_clienttag clienttag;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /ladderinfo <rank> [clienttag]");
        return 0;
    }
    if (str_to_uint(dest,&rank)<0 || rank<1)
    {
        message_send_text(c,message_type_error,c,"Invalid rank.");
        return 0;
    }

    if (text[i]!='\0') {
        if (strlen(text)!=4) {
            message_send_text(c,message_type_error,c,"You must supply a rank and a valid program ID.");
            message_send_text(c,message_type_error,c,"Example: /ladderinfo 1 STAR");
            return 0;
        }
        clienttag = tag_case_str_to_uint(&text[i]);
    } else if (!(clienttag = conn_get_clienttag(c)))
    {
        message_send_text(c,message_type_error,c,"Unable to determine client game.");
        return 0;
    }
    if (clienttag==CLIENTTAG_STARCRAFT_UINT)
    {
        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_active,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal)))
        {
            sprintf(msgtemp,"Starcraft active  %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_active_wins(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),
                    account_get_ladder_active_losses(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),
                    account_get_ladder_active_disconnects(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),
                    account_get_ladder_active_rating(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal));
        }
        else
            sprintf(msgtemp,"Starcraft active  %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_current,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal)))
        {
            sprintf(msgtemp,"Starcraft current %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_wins(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),
                    account_get_ladder_losses(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),
                    account_get_ladder_disconnects(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),
                    account_get_ladder_rating(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal));
        }
        else
            sprintf(msgtemp,"Starcraft current %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);
    }
    else if (clienttag==CLIENTTAG_BROODWARS_UINT)
    {
        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_active,CLIENTTAG_BROODWARS_UINT,ladder_id_normal)))
        {
            sprintf(msgtemp,"Brood War active  %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_active_wins(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal),
                    account_get_ladder_active_losses(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal),
                    account_get_ladder_active_disconnects(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal),
                    account_get_ladder_active_rating(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal));
        }
        else
            sprintf(msgtemp,"Brood War active  %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_current,CLIENTTAG_BROODWARS_UINT,ladder_id_normal)))
        {
            sprintf(msgtemp,"Brood War current %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_wins(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal),
                    account_get_ladder_losses(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal),
                    account_get_ladder_disconnects(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal),
                    account_get_ladder_rating(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal));
        }
        else
            sprintf(msgtemp,"Brood War current %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);
    }
    else if (clienttag==CLIENTTAG_WARCIIBNE_UINT)
    {
        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_active,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal)))
        {
            sprintf(msgtemp,"Warcraft II standard active  %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_active_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),
                    account_get_ladder_active_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),
                    account_get_ladder_active_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),
                    account_get_ladder_active_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal));
        }
        else
            sprintf(msgtemp,"Warcraft II standard active  %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_active,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman)))
        {
            sprintf(msgtemp,"Warcraft II IronMan active   %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_active_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),
                    account_get_ladder_active_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),
                    account_get_ladder_active_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),
                    account_get_ladder_active_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman));
        }
        else
            sprintf(msgtemp,"Warcraft II IronMan active   %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_current,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal)))
        {
            sprintf(msgtemp,"Warcraft II standard current %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),
                    account_get_ladder_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),
                    account_get_ladder_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),
                    account_get_ladder_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal));
        }
        else
            sprintf(msgtemp,"Warcraft II standard current %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account_by_rank(rank,ladder_sort_highestrated,ladder_time_current,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman)))
        {
            sprintf(msgtemp,"Warcraft II IronMan current  %5u: %-20.20s %u/%u/%u rating %u",
                    rank,
                    account_get_name(account),
                    account_get_ladder_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),
                    account_get_ladder_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),
                    account_get_ladder_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),
                    account_get_ladder_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman));
        }
        else
            sprintf(msgtemp,"Warcraft II IronMan current  %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);
    }
    // --> aaron
    else if (clienttag==CLIENTTAG_WARCRAFT3_UINT || clienttag==CLIENTTAG_WAR3XP_UINT)
    {
        unsigned int teamcount = 0;
        if ((account = ladder_get_account(solo_ladder(clienttag),rank,&teamcount,clienttag)))
        {
            sprintf(msgtemp,"WarCraft3 Solo   %5u: %-20.20s %u/%u/0",
                    rank,
                    account_get_name(account),
                    account_get_ladder_wins(account,clienttag,ladder_id_solo),
                    account_get_ladder_losses(account,clienttag,ladder_id_solo));
        }
        else
            sprintf(msgtemp,"WarCraft3 Solo   %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account(team_ladder(clienttag),rank,&teamcount,clienttag)))
        {
            sprintf(msgtemp,"WarCraft3 Team   %5u: %-20.20s %u/%u/0",
                    rank,
                    account_get_name(account),
                    account_get_ladder_wins(account,clienttag,ladder_id_team),
                    account_get_ladder_losses(account,clienttag,ladder_id_team));
        }
        else
            sprintf(msgtemp,"WarCraft3 Team   %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account(ffa_ladder(clienttag),rank,&teamcount,clienttag)))
        {
            sprintf(msgtemp,"WarCraft3 FFA   %5u: %-20.20s %u/%u/0",
                    rank,
                    account_get_name(account),
                    account_get_ladder_wins(account,clienttag,ladder_id_ffa),
                    account_get_ladder_losses(account,clienttag,ladder_id_ffa));
        }
        else
            sprintf(msgtemp,"WarCraft3 FFA   %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);

        if ((account = ladder_get_account(at_ladder(clienttag),rank,&teamcount,clienttag)))
        {
            /*
              if (account_get_atteammembers(account,teamcount,clienttag))
                sprintf(msgtemp,"WarCraft3 AT Team   %5u: %-80.80s %u/%u/0",
            	    rank,
            	    account_get_atteammembers(account,teamcount,clienttag),
            	    account_get_atteamwin(account,teamcount,clienttag),
            	    account_get_atteamloss(account,teamcount,clienttag));

              else */
            sprintf(msgtemp,"WarCraft3 AT Team   %5u: <invalid team info>",rank);
        }
        else
            sprintf(msgtemp,"WarCraft3 AT Team  %5u: <none>",rank);
        message_send_text(c,message_type_info,c,msgtemp);
    }
    //<---
    else
    {
        message_send_text(c,message_type_error,c,"This game does not support win/loss records.");
        message_send_text(c,message_type_error,c,"You must supply a rank and a valid program ID.");
        message_send_text(c,message_type_error,c,"Example: /ladderinfo 1 STAR");
    }

    return 0;
}

static int _handle_timer_command(t_connection * c, char const *text)
{
    unsigned int i,j;
    unsigned int delta;
    char         deltastr[64];
    t_timer_data data;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get comm */
        if (j<sizeof(deltastr)-1) deltastr[j++] = text[i];
    deltastr[j] = '\0';
    for (; text[i]==' '; i++);

    if (deltastr[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /timer <duration>");
        return 0;
    }

    if (clockstr_to_seconds(deltastr,&delta)<0)
    {
        message_send_text(c,message_type_error,c,"Invalid duration.");
        return 0;
    }

    if (text[i]=='\0')
        data.p = xstrdup("Your timer has expired.");
    else
        data.p = xstrdup(&text[i]);

    if (timerlist_add_timer(c,time(NULL)+(time_t)delta,user_timer_cb,data)<0)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"could not add timer");
        xfree(data.p);
        message_send_text(c,message_type_error,c,"Could not set timer.");
    }
    else
    {
        sprintf(msgtemp,"Timer set for %s",seconds_to_timestr(delta));
        message_send_text(c,message_type_info,c,msgtemp);
    }

    return 0;
}

static int _handle_serverban_command(t_connection *c, char const *text)
{
    char dest[USER_NAME_MAX];
    char messagetemp[MAX_MESSAGE_LEN];
    t_connection * dest_c;
    unsigned int i,j;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); // skip command
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) // get dest
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /serverban <account>");
        return 0;
    }

    if (!(dest_c = connlist_find_connection_by_accountname(dest)))
    {
        message_send_text(c,message_type_error,c,"That user is not logged on.");
        return 0;
    }
    sprintf(messagetemp,"Banning User %s who is using IP %s",conn_get_username(dest_c),addr_num_to_ip_str(conn_get_game_addr(dest_c)));
    message_send_text(c,message_type_info,c,messagetemp);
    message_send_text(c,message_type_info,c,"Users Account is also LOCKED! Only a Admin can Unlock it!");
    sprintf(msgtemp,"/ipban a %s",addr_num_to_ip_str(conn_get_game_addr(dest_c)));
    handle_ipban_command(c,msgtemp);
    account_set_auth_lock(conn_get_account(dest_c),1);
    //now kill the connection
    sprintf(msgtemp,"You have been banned by Admin: %s",conn_get_username(c));
    message_send_text(dest_c,message_type_error,dest_c,msgtemp);
    message_send_text(dest_c,message_type_error,dest_c,"Your account is also LOCKED! Only a admin can UNLOCK it!");
    conn_set_state(dest_c, conn_state_destroy);
    return 0;
}

static int _handle_netinfo_command(t_connection * c, char const *text)
{
    char           dest[USER_NAME_MAX];
    unsigned int   i,j;
    t_connection * conn;
    t_game const * game;
    unsigned int   addr;
    unsigned short port;
    unsigned int   taddr;
    unsigned short tport;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); // skip command
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) // get dest
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
        strcpy(dest,conn_get_username(c));

    if (!(conn = connlist_find_connection_by_accountname(dest)))
    {
        message_send_text(c,message_type_error,c,"That user is not logged on.");
        return 0;
    }

    if (conn_get_account(conn)!=conn_get_account(c) &&
            prefs_get_hide_addr() && !(account_get_command_groups(conn_get_account(c)) & command_get_group("/admin-addr"))) // default to false
    {
        message_send_text(c,message_type_error,c,"Address information for other users is only available to admins.");
        return 0;
    }

    sprintf(msgtemp,"Server TCP: %s (bind %s)",addr_num_to_addr_str(conn_get_real_local_addr(conn),conn_get_real_local_port(conn)),addr_num_to_addr_str(conn_get_local_addr(conn),conn_get_local_port(conn)));
    message_send_text(c,message_type_info,c,msgtemp);

    sprintf(msgtemp,"Client TCP: %s",addr_num_to_addr_str(conn_get_addr(conn),conn_get_port(conn)));
    message_send_text(c,message_type_info,c,msgtemp);

    taddr=addr = conn_get_game_addr(conn);
    tport=port = conn_get_game_port(conn);
    trans_net(conn_get_addr(c),&taddr,&tport);

    if (taddr==addr && tport==port)
        sprintf(msgtemp,"Client UDP: %s",
                addr_num_to_addr_str(addr,port));
    else
        sprintf(msgtemp,"Client UDP: %s (trans %s)",
                addr_num_to_addr_str(addr,port),
                addr_num_to_addr_str(taddr,tport));
    message_send_text(c,message_type_info,c,msgtemp);

    if ((game = conn_get_game(conn)))
    {
        taddr=addr = game_get_addr(game);
        tport=port = game_get_port(game);
        trans_net(conn_get_addr(c),&taddr,&tport);

        if (taddr==addr && tport==port)
            sprintf(msgtemp,"Game UDP:  %s",
                    addr_num_to_addr_str(addr,port));
        else
            sprintf(msgtemp,"Game UDP:  %s (trans %s)",
                    addr_num_to_addr_str(addr,port),
                    addr_num_to_addr_str(taddr,tport));
    }
    else
        strcpy(msgtemp,"Game UDP:  none");
    message_send_text(c,message_type_info,c,msgtemp);

    return 0;
}

static int _handle_quota_command(t_connection * c, char const * text)
{
    sprintf(msgtemp,"Your quota allows you to write %u lines per %u seconds.",prefs_get_quota_lines(),prefs_get_quota_time());
    message_send_text(c,message_type_info,c,msgtemp);
    sprintf(msgtemp,"Long lines will be considered to wrap every %u characters.",prefs_get_quota_wrapline());
    message_send_text(c,message_type_info,c,msgtemp);
    sprintf(msgtemp,"You are not allowed to send lines with more than %u characters.",prefs_get_quota_maxline());
    message_send_text(c,message_type_info,c,msgtemp);

    return 0;
}

static int _handle_lockacct_command(t_connection * c, char const *text)
{
    t_connection * user;
    t_account *    account;

    text = skip_command(text);

    if (text[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /lockacct <username>");
        return 0;
    }

    if (!(account = accountlist_find_account(text)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }
    if ((user = connlist_find_connection_by_accountname(text)))
        message_send_text(user,message_type_info,user,"Your account has just been locked by admin.");

    account_set_auth_lock(account,1);
    message_send_text(c,message_type_error,c,"That user account is now locked.");
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
    return 0;
}

static int _handle_unlockacct_command(t_connection * c, char const *text)
{
    t_connection * user;
    t_account *    account;

    text = skip_command(text);

    if (text[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /unlockacct <username>");
        return 0;
    }
    if (!(account = accountlist_find_account(text)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }

    if ((user = connlist_find_connection_by_accountname(text)))
        message_send_text(user,message_type_info,user,"Your account has just been unlocked by admin.");

    account_set_auth_lock(account,0);
    message_send_text(c,message_type_error,c,"That user account is now unlocked.");
    return 0;
}

static int _handle_flag_command(t_connection * c, char const *text)
{
    char         dest[32];
    unsigned int i,j;
    unsigned int newflag;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /flag <flag>");
        return 0;
    }

    newflag = strtoul(dest,NULL,0);
    conn_set_flags(c,newflag);

    sprintf(msgtemp,"Flags set to 0x%08x.",newflag);
    message_send_text(c,message_type_info,c,msgtemp);
    return 0;
}

static int _handle_tag_command(t_connection * c, char const *text)
{
    char         dest[8];
    unsigned int i,j;
    unsigned int newtag;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);
    for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest */
        if (j<sizeof(dest)-1) dest[j++] = text[i];
    dest[j] = '\0';
    for (; text[i]==' '; i++);

    if (dest[0]=='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /tag <clienttag>");
        return 0;
    }
    if (strlen(dest)!=4)
    {
        message_send_text(c,message_type_error,c,"Client tag should be four characters long.");
        return 0;
    }
    newtag = tag_case_str_to_uint(dest);
    if (tag_check_client(newtag))
    {
        unsigned int oldflags = conn_get_flags(c);
        conn_set_clienttag(c,newtag);
        if ((newtag==CLIENTTAG_WARCRAFT3_UINT) || (newtag==CLIENTTAG_WAR3XP_UINT))
            conn_update_w3_playerinfo(c);
        channel_rejoin(c);
        conn_set_flags(c,oldflags);
        channel_update_userflags(c);
        sprintf(msgtemp,"Client tag set to %s.",dest);
    }
    else
        sprintf(msgtemp,"Invalid clienttag %s specified",dest);
    message_send_text(c,message_type_info,c,msgtemp);
    return 0;
}

static int _handle_set_command(t_connection * c, char const *text)
{
    t_account * account;
    char *accname;
    char *key;
    char *value;
    char t[MAX_MESSAGE_LEN];
    unsigned int i,j;
    char         arg1[256];
    char         arg2[256];
    char         arg3[256];

    strncpy(t, text, MAX_MESSAGE_LEN - 1);
    for (i=0; t[i]!=' ' && t[i]!='\0'; i++); /* skip command /set */

    for (; t[i]==' '; i++); /* skip spaces */
    for (j=0; t[i]!=' ' && t[i]!='\0'; i++) /* get username */
        if (j<sizeof(arg1)-1) arg1[j++] = t[i];
    arg1[j] = '\0';

    for (; t[i]==' '; i++); /* skip spaces */
    for (j=0; t[i]!=' ' && t[i]!='\0'; i++) /* get key */
        if (j<sizeof(arg2)-1) arg2[j++] = t[i];
    arg2[j] = '\0';

    for (; t[i]==' '; i++); /* skip spaces */
    for (j=0; t[i]!='\0'; i++) /* get value */
        if (j<sizeof(arg3)-1) arg3[j++] = t[i];
    arg3[j] = '\0';

    accname = arg1;
    key     = arg2;
    value   = arg3;

    if ((arg1[0] =='\0') || (arg2[0]=='\0'))
    {
        message_send_text(c,message_type_info,c,"usage: /set <username> <key> [value]");
    }

    if (!(account = accountlist_find_account(accname)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }

    if (*value == '\0')
    {
        if (account_get_strattr(account,key))
        {
            sprintf(msgtemp, "current value of %.64s is \"%.128s\"",key,account_get_strattr(account,key));
            message_send_text(c,message_type_error,c,msgtemp);
        }
        else
            message_send_text(c,message_type_error,c,"value currently not set");
        return 0;
    }

    if (account_set_strattr(account,key,value)<0)
        message_send_text(c,message_type_error,c,"Unable to set key");
    else
        message_send_text(c,message_type_error,c,"Key set succesfully");
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);

    return 0;
}

static int _handle_motd_command(t_connection * c, char const *text)
{
    char const * filename;
    FILE *       fp;

    if ((filename = prefs_get_motdfile())) {
        if ((fp = fopen(filename,"r")))
        {
            message_send_file(c,fp);
            if (fclose(fp)<0)
                eventlog(eventlog_level_error,__FUNCTION__,"could not close motd file \"%s\" after reading (fopen: %s)",filename,pstrerror(errno));
        }
        else
        {
            eventlog(eventlog_level_error,__FUNCTION__,"could not open motd file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno));
            message_send_text(c,message_type_error,c,"Unable to open motd.");
        }
        return 0;
    } else {
        message_send_text(c,message_type_error,c,"No motd.");
        return 0;
    }
}

static int _handle_ping_command(t_connection * c, char const *text)
{
    unsigned int i;
    t_connection *	user;
    t_game 	*	game;

    for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */
    for (; text[i]==' '; i++);

    if (text[i]=='\0')
    {
        if ((game=conn_get_game(c)))
        {
            for (i=0; i<game_get_count(game); i++)
            {
                if ((user = game_get_player_conn(game, i)))
                {
                    sprintf(msgtemp,"%s latency: %9u",conn_get_username(user),conn_get_latency(user));
                    message_send_text(c,message_type_info,c,msgtemp);
                }
            }
            return 0;
        }
        sprintf(msgtemp,"Your latency %9u",conn_get_latency(c));
    }
    else if ((user = connlist_find_connection_by_accountname(&text[i])))
        sprintf(msgtemp,"%s latency %9u",&text[i],conn_get_latency(user));
    else
        sprintf(msgtemp,"Invalid user");

    message_send_text(c,message_type_info,c,msgtemp);
    return 0;
}

/* Redirected to handle_ipban_command in ipban.c [Omega]
static int _handle_ipban_command(t_connection * c, char const *text)
{
  handle_ipban_command(c,text);
  return 0;
}
*/

static int _handle_commandgroups_command(t_connection * c, char const * text)
{
    t_account *	account;
    char *	command;
    char *	username;
    unsigned int usergroups;	// from user account
    unsigned int groups = 0;	// converted from arg3
    char	tempgroups[8];	// converted from usergroups
    char 	t[MAX_MESSAGE_LEN];
    unsigned int i,j;
    char	arg1[256];
    char	arg2[256];
    char	arg3[256];

    strncpy(t, text, MAX_MESSAGE_LEN - 1);
    for (i=0; t[i]!=' ' && t[i]!='\0'; i++); /* skip command /groups */

    for (; t[i]==' '; i++); /* skip spaces */
    for (j=0; t[i]!=' ' && t[i]!='\0'; i++) /* get command */
        if (j<sizeof(arg1)-1) arg1[j++] = t[i];
    arg1[j] = '\0';

    for (; t[i]==' '; i++); /* skip spaces */
    for (j=0; t[i]!=' ' && t[i]!='\0'; i++) /* get username */
        if (j<sizeof(arg2)-1) arg2[j++] = t[i];
    arg2[j] = '\0';

    for (; t[i]==' '; i++); /* skip spaces */
    for (j=0; t[i]!='\0'; i++) /* get groups */
        if (j<sizeof(arg3)-1) arg3[j++] = t[i];
    arg3[j] = '\0';

    command = arg1;
    username = arg2;

    if (arg1[0] =='\0') {
        message_send_text(c,message_type_info,c,"usage: /cg <command> <username> [<group(s)>]");
        return 0;
    }

    if (!strcmp(command,"help") || !strcmp(command,"h")) {
        message_send_text(c,message_type_info,c,"Command Groups (Defines the Groups of Commands a User Can Use.)");
        message_send_text(c,message_type_info,c,"Type: /cg add <username> <group(s)> - adds group(s) to user profile");
        message_send_text(c,message_type_info,c,"Type: /cg del <username> <group(s)> - deletes group(s) from user profile");
        message_send_text(c,message_type_info,c,"Type: /cg list <username> - shows current groups user can use");
        return 0;
    }

    if (arg2[0] =='\0') {
        message_send_text(c,message_type_info,c,"usage: /cg <command> <username> [<group(s)>]");
        return 0;
    }

    if (!(account = accountlist_find_account(username))) {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }

    usergroups = account_get_command_groups(account);

    if (!strcmp(command,"list") || !strcmp(command,"l")) {
        if (usergroups & 1) tempgroups[0] = '1'; else tempgroups[0] = ' ';
        if (usergroups & 2) tempgroups[1] = '2'; else tempgroups[1] = ' ';
        if (usergroups & 4) tempgroups[2] = '3'; else tempgroups[2] = ' ';
        if (usergroups & 8) tempgroups[3] = '4'; else tempgroups[3] = ' ';
        if (usergroups & 16) tempgroups[4] = '5'; else tempgroups[4] = ' ';
        if (usergroups & 32) tempgroups[5] = '6'; else tempgroups[5] = ' ';
        if (usergroups & 64) tempgroups[6] = '7'; else tempgroups[6] = ' ';
        if (usergroups & 128) tempgroups[7] = '8'; else tempgroups[7] = ' ';
        sprintf(msgtemp, "%s's command group(s): %s", username, tempgroups);
        message_send_text(c,message_type_info,c,msgtemp);
        return 0;
    }

    if (arg3[0] =='\0') {
        message_send_text(c,message_type_info,c,"usage: /cg <command> <username> [<group(s)>]");
        return 0;
    }

    for (i=0; arg3[i] != '\0'; i++) {
        if (arg3[i] == '1') groups |= 1;
        else if (arg3[i] == '2') groups |= 2;
        else if (arg3[i] == '3') groups |= 4;
        else if (arg3[i] == '4') groups |= 8;
        else if (arg3[i] == '5') groups |= 16;
        else if (arg3[i] == '6') groups |= 32;
        else if (arg3[i] == '7') groups |= 64;
        else if (arg3[i] == '8') groups |= 128;
        else {
            sprintf(msgtemp, "got bad group: %c", arg3[i]);
            message_send_text(c,message_type_info,c,msgtemp);
            return 0;
        }
    }
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);

    if (!strcmp(command,"add") || !strcmp(command,"a")) {
        account_set_command_groups(account, usergroups | groups);
        sprintf(msgtemp, "groups %s has been added to user: %s", arg3, username);
        message_send_text(c,message_type_info,c,msgtemp);
        return 0;
    }

    if (!strcmp(command,"del") || !strcmp(command,"d")) {
        account_set_command_groups(account, usergroups & (255 - groups));
        sprintf(msgtemp, "groups %s has been deleted from user: %s", arg3, username);
        message_send_text(c,message_type_info,c,msgtemp);
        return 0;
    }

    sprintf(msgtemp, "got unknown command: %s", command);
    message_send_text(c,message_type_info,c,msgtemp);
    return 0;
}

static int _handle_topic_command(t_connection * c, char const * _text)
{
    string channel_name;
    string topic;
    t_channel * channel;
    int  do_save = NO_SAVE_TOPIC;
	string text(_text);

    channel_name = text.c_str();
	BOOST_AUTO(topic_begin,find(text.begin(),text.end(),'"'));
	BOOST_AUTO(topic_end,find(topic_begin + 1,text.end(),'"'));
	if(topic_end != text.end())
    {
		channel_name.assign(text.begin(),topic_begin);
		topic.assign(topic_begin,topic_end - 1);
    }

    if (!(conn_get_channel(c))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

    if(!(topic.length()))
    {
        if (channel_get_topic(channel_get_name(conn_get_channel(c))))
        {
            sprintf(msgtemp,"%s topic: %s",channel_get_name(conn_get_channel(c)),channel_get_topic(channel_get_name(conn_get_channel(c))));
        }
        else
        {
            sprintf(msgtemp,"%s topic: no topic",channel_get_name(conn_get_channel(c)));
        }
        message_send_text(c,message_type_info,c,msgtemp);

        return 0;
    }

    if (channel_name[0]=='\0')
    {
        if (channel_get_topic(channel_get_name(conn_get_channel(c))))
        {
            sprintf(msgtemp,"%s topic: %s",channel_get_name(conn_get_channel(c)),channel_get_topic(channel_get_name(conn_get_channel(c))));
        }
        else
        {
            sprintf(msgtemp,"%s topic: no topic",channel_get_name(conn_get_channel(c)));
        }
        message_send_text(c,message_type_info,c,msgtemp);
        return 0;
    }

    if (!(account_is_operator_or_admin(conn_get_account(c),channel_get_name(conn_get_channel(c))))) {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Operator to use this command.");
        return -1;
    }

    if (!(channel = conn_get_channel(c)))
    {
        sprintf(msgtemp,"no such channel, can't set topic");
        message_send_text(c,message_type_error,c,msgtemp);
        return -1;
    }

  if (topic.length() >= MAX_TOPIC_LEN) 
     { 
       sprintf(msgtemp,"max topic length exceeded (max %d symbols)", MAX_TOPIC_LEN); 
       message_send_text(c,message_type_error,c,msgtemp); 
       return -1; 
     } 
    if (channel_get_permanent(channel))
	{
        do_save = DO_SAVE_TOPIC;
	    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
	}
    

    channel_name = channel_get_name(channel);

    channel_set_topic(channel_name.c_str(), topic.c_str(), do_save);

    sprintf(msgtemp,"%s topic: %s",channel_name, topic);
    message_send_text(c,message_type_info,c,msgtemp);

    return 0;
}

static int _handle_moderate_command(t_connection * c, char const * text)
{
    t_channel_flags oldflags;
    t_channel * channel;

    if (!(channel = conn_get_channel(c))) {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return -1;
    }

/*    if (!(account_is_operator_or_admin(conn_get_account(c),channel_get_name(channel)))) {
        message_send_text(c,message_type_error,c,"You must be at least a Channel Operator to use this command.");
        return -1;
    }*/

    oldflags = channel_get_flags(channel);

    if (channel_set_flags(channel, oldflags ^ channel_flags_moderated)) {
        eventlog(eventlog_level_error,__FUNCTION__,"could not set channel %s flags",channel_get_name(channel));
        message_send_text(c,message_type_error,c,"Unable to change channel flags.");
        return -1;
    }
    else {
        if (oldflags & channel_flags_moderated)
            channel_message_send(channel,message_type_info,c,"Channel is now unmoderated");
        else
            channel_message_send(channel,message_type_info,c,"Channel is now moderated");
    }

    return 0;
}

static void _reset_d1_stats(t_account *account, t_clienttag ctag, t_connection *c)
{
    account_set_normal_level(account,ctag,0);
    account_set_normal_strength(account,ctag,0),
    account_set_normal_magic(account,ctag,0),
    account_set_normal_dexterity(account,ctag,0),
    account_set_normal_vitality(account,ctag,0),
    account_set_normal_gold(account,ctag,0);

    sprintf(msgtemp,"Resetted %s's %s Stats",account_get_name(account),clienttag_get_title(ctag));
    message_send_text(c,message_type_info,c,msgtemp);
}

static void _reset_scw2_stats(t_account *account, t_clienttag ctag, t_connection *c)
{
    account_set_normal_wins(account,ctag,0);
    account_set_normal_losses(account,ctag,0);
    account_set_normal_disconnects(account,ctag,0);

    if (account_get_ladder_rating(account,ctag,ladder_id_normal)>0) {
        account_set_ladder_wins(account,ctag,ladder_id_normal,0);
        account_set_ladder_losses(account,ctag,ladder_id_normal,0);
        account_set_ladder_disconnects(account,ctag,ladder_id_normal,0);
        account_set_ladder_rating(account,ctag,ladder_id_normal,0);
    }

    if (account_get_ladder_rating(account,ctag,ladder_id_ironman)>0) {
        account_set_ladder_wins(account,ctag,ladder_id_ironman,0);
        account_set_ladder_losses(account,ctag,ladder_id_ironman,0);
        account_set_ladder_disconnects(account,ctag,ladder_id_ironman,0);
        account_set_ladder_rating(account,ctag,ladder_id_ironman,0);
    }

    sprintf(msgtemp,"Resetted %s's %s Stats",account_get_name(account),clienttag_get_title(ctag));
    message_send_text(c,message_type_info,c,msgtemp);
}

static void _reset_w3_stats(t_account *account, t_clienttag ctag, t_connection *c)
{
    account_set_ladder_level(account,ctag,ladder_id_solo,0);
    account_set_ladder_xp(account,ctag,ladder_id_solo,0);
    account_set_ladder_wins(account,ctag,ladder_id_solo,0);
    account_set_ladder_losses(account,ctag,ladder_id_solo,0);
    account_set_ladder_rank(account,ctag,ladder_id_solo,0);

    account_set_ladder_level(account,ctag,ladder_id_team,0);
    account_set_ladder_xp(account,ctag,ladder_id_team,0);
    account_set_ladder_wins(account,ctag,ladder_id_team,0);
    account_set_ladder_losses(account,ctag,ladder_id_team,0);
    account_set_ladder_rank(account,ctag,ladder_id_team,0);

    account_set_ladder_level(account,ctag,ladder_id_ffa,0);
    account_set_ladder_xp(account,ctag,ladder_id_ffa,0);
    account_set_ladder_wins(account,ctag,ladder_id_ffa,0);
    account_set_ladder_losses(account,ctag,ladder_id_ffa,0);
    account_set_ladder_rank(account,ctag,ladder_id_ffa,0);
    // this would now need a way to delete the team for all members now
    //account_set_atteamcount(account,ctag,0);

    sprintf(msgtemp,"Resetted %s's %s Stats",account_get_name(account),clienttag_get_title(ctag));
    message_send_text(c,message_type_info,c,msgtemp);
}

static int _handle_clearstats_command(t_connection *c, char const *text)
{

    /*
        unsigned int i,j,all;
        t_account *  account;
        t_clienttag  ctag = 0;
        char         dest[USER_NAME_MAX];
        for (i=0; text[i]!=' ' && text[i]!='\0'; i++);
        for (; text[i]==' '; i++);

        if (!text[i]) {
            message_send_text(c,message_type_error,c,"Missing user, syntax error.");
            message_send_text(c,message_type_error,c,"Usage example: /clearstats <username> <clienttag>");
            message_send_text(c,message_type_error,c,"  where <clienttag> can be any valid client or ALL for all clients");
            return 0;
        }

        for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get dest *
            if (j<sizeof(dest)-1) dest[j++] = text[i];
        dest[j] = '\0';

        account = accountlist_find_account(dest);
        if (!account) {
            message_send_text(c,message_type_error,c,"Invalid user.");
            return 0;
        }

        for (; text[i]==' '; i++);
        if (!text[i]) {
            message_send_text(c,message_type_error,c,"Missing clienttag, syntax error.");
            message_send_text(c,message_type_error,c,"Usage example: /clearstats <username> <clienttag>");
            message_send_text(c,message_type_error,c,"  where <clienttag> can be any valid client or ALL for all clients");
            return 0;
        }

        if (strcasecmp(text + i,"all")) {
            if (strlen(text + i) != 4) {
                message_send_text(c,message_type_error,c,"Invalid clienttag, syntax error.");
                return 0;
            }
            ctag = tag_case_str_to_uint(text + i);
            all = 0;
        } else all = 1;
    /*
        if (all || ctag == CLIENTTAG_DIABLORTL_UINT)
            _reset_d1_stats(account,CLIENTTAG_DIABLORTL_UINT,c);

        if (all || ctag == CLIENTTAG_DIABLOSHR_UINT)
            _reset_d1_stats(account,CLIENTTAG_DIABLOSHR_UINT,c);

        if (all || ctag == CLIENTTAG_WARCIIBNE_UINT)
            _reset_scw2_stats(account,CLIENTTAG_WARCIIBNE_UINT,c);

        if (all || ctag == CLIENTTAG_STARCRAFT_UINT)
            _reset_scw2_stats(account,CLIENTTAG_STARCRAFT_UINT,c);
    */
    /*
        if (all || ctag == CLIENTTAG_SHAREWARE_UINT)
            _reset_scw2_stats(account,CLIENTTAG_SHAREWARE_UINT,c);

        if (all || ctag == CLIENTTAG_WARCRAFT3_UINT)
            _reset_w3_stats(account,CLIENTTAG_WARCRAFT3_UINT,c);

        if (all || ctag == CLIENTTAG_WAR3XP_UINT)
            _reset_w3_stats(account,CLIENTTAG_WAR3XP_UINT,c);*/
    _reset_scw2_stats(conn_get_account(c),CLIENTTAG_BROODWARS_UINT,c);
    account_set_numattr(conn_get_account(c),"BNET\\acct\\durtime",0);

    return 0;
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

static int _handle_icon_command(t_connection * c, char const *text)
{
    t_account * account;
    t_account  *	accfrom;
    char *accname;
    unsigned int i,j;
	char	const		*tagfrom=0;
	char	const		*tagto=0;
    t_channel const * channel;
    t_connection *	kuc=0;


	accname=(char*)(text = skip_command(text));

    if (accname[0] =='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /icon <username>");
    }
    //                          eventlog(eventlog_level_debug,__FUNCTION__," : %d",__LINE__);

    if (!(account = accountlist_find_account(accname)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }
    if (!(accfrom = conn_get_account(c)))
    {
        message_send_text(c,message_type_error,c,"ERROR! Invalid user.");
        return 0;
    }
    if (!(channel = conn_get_channel(c)))
    {
        message_send_text(c,message_type_error,c,"This command can only be used inside a channel.");
        return 0;
    }
    if (account_get_auth_admin(accfrom,NULL)!=1 && /* default to false */
            account_get_auth_admin(accfrom,channel_get_name(channel))!=1 && /* default to false */
            account_get_auth_operator(accfrom,NULL)!=1 && /* default to false */
            account_get_auth_operator(accfrom,channel_get_name(channel))!=1)
    {
        message_send_text(c,message_type_error,c,"You have to be at least a Channel Operator or tempOP to use this command.");
        return 0;
    }
    //                          eventlog(eventlog_level_debug,__FUNCTION__," : %d",__LINE__);



    if(!(tagfrom=account_get_strattr(accfrom,"BNET\\iconmaster")))
    {
        message_send_text(c,message_type_error,c,"/icon, tagfrom");
        return 0;
    }
    //	if(!
    tagto=account_get_strattr(account,"BNET\\fakeclienttag");
    //		)
    //	{
    //		message_send_text(c,message_type_error,c,"/icon, tagto");
    //		account_unget_strattr(tagfrom);
    //		return 0;
    //	}
    //		tagto=account_get_strattr(account,"BNET\\fakeclienttag");
    if(strlen(tagfrom)==4)
    {
        if((tagto)?(strcmp(tagto,tagfrom)):1)
        {
            if (!(kuc = connlist_find_connection_by_accountname(accname)))
            {
                message_send_text(c,message_type_error,c,"That user is not logged in.");
                return 0;
            }
            if (conn_get_channel(kuc)!=channel)
            {
                message_send_text(c,message_type_error,c,"That user is not in this channel.");
                return 0;
            }
            if((tagto)?(strlen(tagto)==4 && strcmp(tagto,"SEXP")):0)
            {
                message_send_text(c,message_type_error,c,"Icon Should be Clear, Before Set Icon");
                return 0;
            }

            account_set_strattr(account,"BNET\\fakeclienttag",tagfrom);
            message_send_text(c,message_type_error,c,"Seted Icon");
        }
        else
        {
            account_set_strattr(account,"BNET\\fakeclienttag","SEXP");
            message_send_text(c,message_type_error,c,"Cleard Icon");
        }
    }
    else
    {
        message_send_text(c,message_type_error,c,"You Can't Give Icon To Others");
    }
    //	if(tagto)account_unget_strattr(tagto);
    //	account_unget_strattr(tagfrom);
    if(kuc)command_set_flags(kuc);
    return 0;
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

static int check_ladder(t_account * account)
{
    if(account_get_numattr(account,"BNET\\acct\\durtime")>=720)return 1;
    return 0;
}


static int _handle_lgame_command(t_connection * c, char const *text)
{
    int k;

    t_account * account;
	char const *accname;
    unsigned int i,j;


    accname=text = skip_command(text);

    if (accname[0] =='\0')
    {
        if (!(account = conn_get_account(c)))
        {
			message_send_text(c,message_type_error,c,"사용자 정보 에러");
            return 0;
        }
    }
    else
    {
        if (!(account = accountlist_find_account(accname)))
        {
			message_send_text(c,message_type_error,c,"존재하지 않는 유저입니다");
            return 0;
        }
    }

	if(check_ladder(account))message_send_text(c,message_type_info,c,"레더게임 가능합니다");
	else message_send_text(c,message_type_info,c,"레더게임이 불가능합니다.");
	return 0;
}

static int _handle_lwith_command(t_connection * c, char const *text)
{
    int k;
	char const *accname;
    unsigned int i,j;
    int uid,l=0,ttt=1;
    char const *in=0;
    char ustr[6];
    int aa,bb,cc;
    t_account *account,*self;

    accname=text = skip_command(text);


    if (accname[0] =='\0')
    {
		message_send_text(c,message_type_error,c,"상대방의 ID 를 입력해 주세요");
        return 0;
    }
    if (!(account = accountlist_find_account(accname)))
    {
		message_send_text(c,message_type_error,c,"존재하지 않는 유저입니다");
        return 0;
    }
    if(!(self=conn_get_account(c)))
    {
		message_send_text(c,message_type_error,c,"사용자 정보 에러");
        return 0;
    }
    ttt=1;

    if(!check_ladder(self))ttt=0;
    if(!check_ladder(account))ttt=0;

    if(ttt)
    {
        ttt=1;
        l=0;
        in=0;

        uid=account_get_uid(self);
        j=uid;
        for(k=0;k<5;k++)
        {
            ustr[k]='!';
        }
        for(k=4;k>=0;k--)
        {
            ustr[k]='!'+(j%58);
            if(j<58)break;
            j-=(j%58);
            j/=58;
        }
        ustr[5]=0;
        in=account_get_strattr(account,"BNET\\played");
        if(in)
        {
            for(k=0;k<240;k+=5)
            {
                if(in[k]==0)break;
                if(in[k+1]==0)break;
                if(in[k+2]==0)break;
                if(in[k+3]==0)break;
                if(in[k+4]==0)break;
                if(strncmp(in+k,ustr,5)==0)
                {
                    l++;
                    if(l>=3)
                    {
                        ttt=0;
                        break;
                    }
                }
            }
        }

        if(ttt)
        {
            l=0;
            in=0;

            uid=account_get_uid(account);
            j=uid;
            for(k=0;k<5;k++)
            {
                ustr[k]='!';
            }
            for(k=4;k>=0;k--)
            {
                ustr[k]='!'+(j%58);
                if(j<58)break;
                j-=(j%58);
                j/=58;
            }
            ustr[5]=0;
            in=account_get_strattr(self,"BNET\\played");
            if(in)
            {
                for(k=0;k<240;k+=5)
                {
                    if(in[k]==0)break;
                    if(in[k+1]==0)break;
                    if(in[k+2]==0)break;
                    if(in[k+3]==0)break;
                    if(in[k+4]==0)break;
                    if(strncmp(in+k,ustr,5)==0)
                    {
                        l++;
                        if(l>=3)
                        {
                            ttt=0;
                            break;
                        }
                    }
                }
            }
        }
    }

    {
        aa=account_get_ladder_rating(self,CLIENTTAG_BROODWARS_UINT,1);
        bb=account_get_ladder_rating(account,CLIENTTAG_BROODWARS_UINT,1);
        if(aa>bb)cc=aa-bb;else cc=bb-aa;
        if(aa>=1100&&bb>=1100&&cc<=100)ttt=1;
        if(aa>0&&bb>0&&cc>200)ttt=0;
    }


	if(ttt==1)sprintf(msgtemp,"%s님과 레더게임이 가능합니다",accname);
	else sprintf(msgtemp,"%s님과 레더 게임이 불가합니다",accname);
    message_send_text(c,message_type_info,c,msgtemp);
    return 0;
}


static int _handle_iconadmin_command(t_connection * c, char const *text)
{
    t_account * account;
    t_account  *	accfrom;
	char const *accname;
    unsigned int i,j;
	char	const	* arg1;
	char	const	 * arg2;
    char			*tagfrom=0;
    char			*tagto=0;
    t_channel const * channel;
    t_connection *	kuc;

    arg1=text = skip_command(text);
    arg2=text = skip_command(text);


    accname = arg1;

    if (arg1[0] =='\0'||strlen(arg2)!=4)
    {
        message_send_text(c,message_type_info,c,"usage: /iconadmin <username> <CLANID>");
    }

    if (!(account = accountlist_find_account(accname)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }

    account_set_strattr(account,"BNET\\iconmaster",arg2);
    sprintf(msgtemp,"Iconadmin '%s' to '%s'",arg2,arg1);
    message_send_text(c,message_type_error,c,msgtemp);
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
    return 0;
}


static int _handle_icondel_command(t_connection * c, char const *text)
{
    t_account * account;
    t_account  *	accfrom;
	char const *accname;
    unsigned int i,j;
	char const		* arg1;
    char			*tagfrom=0;
    char			*tagto=0;
    t_channel const * channel;
    t_connection *	kuc;

    arg1=text = skip_command(text);

    accname = arg1;

    if (arg1[0] =='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /icondel <username>");
    }


    if (!(account = accountlist_find_account(accname)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }
    account_set_strattr(account,"BNET\\fakeclienttag","SEXP");
    sprintf(msgtemp,"Icon Del '%s'",arg1);
    message_send_text(c,message_type_error,c,msgtemp);
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
    return 0;
}


static int _handle_clearstatsadmin_command(t_connection * c, char const *text)
{
    t_account * account;
    t_account  *	accfrom;
	char const *accname;
    unsigned int i,j;
	char	const	* arg1;
    char			*tagfrom=0;
    char			*tagto=0;
    t_channel const * channel;
    t_connection *	kuc;

    arg1=text = skip_command(text);

    accname = arg1;

    if (arg1[0] =='\0')
    {
        message_send_text(c,message_type_info,c,"usage: /clearstatsadmin <username>");
    }

    if (!(account = accountlist_find_account(accname)))
    {
        message_send_text(c,message_type_error,c,"Invalid user.");
        return 0;
    }
    _reset_scw2_stats(account,CLIENTTAG_BROODWARS_UINT,c);
    account_set_numattr(account,"BNET\\acct\\durtime",0);
    sprintf(msgtemp,"Clear Stats By Admin '%s'",arg1);
    message_send_text(c,message_type_error,c,msgtemp);
    eventlog(eventlog_level_fatal,__FUNCTION__,"[Command] %s : %s",account_get_name(conn_get_account(c)),text);
    return 0;
}

static int _handle_teamset_command(t_connection * c, char const *text)
{
	char	const	* arg1,*stat;
	char teamname[11];
	int i;

    arg1=text = skip_command(text);

    if (arg1[0] =='\0')
    {
		stat=account_get_strattr(conn_get_account(c),"BNET\\team");
	    sprintf(msgtemp,"'%s'로 팀설정이 되어 있습니다.",stat);
        message_send_text(c,message_type_info,c,msgtemp);
		return 0;
    }

	strncpy(teamname,arg1,10);
	for(i=0;i<strlen(arg1);i++)
		teamname[i]=toupper(teamname[i]);

    account_set_strattr(conn_get_account(c),"BNET\\team",teamname);

    sprintf(msgtemp,"'%s'로 팀설정이 되었습니다.",teamname);
    message_send_text(c,message_type_error,c,msgtemp);
    message_send_text(c,message_type_error,c,"이제 top vs bottom 에서 같은편의 팀설정이 양측 모두 동일하면 ");
    message_send_text(c,message_type_error,c,"팀레더로 진행됩니다");
    return 0;
}

static int _handle_teamcheck_command(t_connection * c, char const *text)
{
   t_game const *    game;
	int error=0;

	game=conn_get_game(c);

	if(!game)
	{
		message_send_text(c,message_type_error,c,"게임안에서 실행가능한 명령입니다.");
		return 0;
	}
	error=_isTeamgame(game,c);

	if(error)
	{
		message_send_text(c,message_type_error,c,"각 team 숫자가 틀립니다.");
		message_send_text(c,message_type_error,c,"팀레더로 경기가 불가능합니다.");
	}
	else
	{
		message_send_text(c,message_type_error,c,"각 team 숫자가 맞습니다.");
		message_send_text(c,message_type_error,c,"팀레더로 경기가 가능합니다.");
	}
    return 0;
}
static int _handle_imhackuser_command(t_connection * c, char const *text)
{
	ipbanlist_add(0,addr_num_to_ip_str(conn_get_addr(c)),0);
	return 0;
}
